【问题标题】:Should I move on return when variables are not local当变量不是本地变量时,我应该继续返回吗
【发布时间】:2022-01-25 00:15:11
【问题描述】:

A 有几个关于复制省略和移动的问题。 假设我有以下代码:

class A {};

class B {
public:
    A get1() const {
        A local_var;
        return local_var;
    }
    A get1bad() const {
        A local_var;
        return std::move(local_var);
    }
    A get2() const {
        return member_var;
    }
    A get3() const {
        return std::move(member_var);
    }
private:
    A member_var;
};

我读过很多人说不要在返回时继续前进。 据我所知,这是因为使用复制省略,在案例 get1 上,编译器不会调用构造函数 + 移动构造函数,而只会调用默认构造函数,而案例 get1bad 会强制编译器调用构造函数 + 移动。

我的问题是关于变量不是本地的情况(get2 vs get3)。 在这种情况下,无论如何都会在类中构造变量。在 get2 中,我认为实际上没有任何优化是可能的。在这种情况下,如果我并不真正关心确保 B 类具有有效的 A 对象,那么实际移动不是更好吗?不就是调用通常比拷贝构造函数便宜的移动构造函数吗?

【问题讨论】:

  • 是的,对于非本地对象,最好通过移动返回,但在您的情况下,成员函数 get3const 所以数据成员 member_var 也将被复制到这里.当你犯了这样的错误时,像 clang-tidy 这样的工具会让你知道。

标签: c++ c++11 move


【解决方案1】:
A get3() const {
    return std::move(member_var);
}

你有一个 const 函数,所以该成员也被认为是 const 并且无论如何都不会移动。

当您有一个临时的B 时,您可以考虑使用A get3() && 移动该成员。也许,如果这种情况经常发生的话。

拥有一个总是会破坏类的值的getter,即使它是一个左值,这似乎是一个罕见的用例。

【讨论】:

  • 谢谢,这就是我想知道的,正在尝试做一个类似 std::future 的类(滚动我自己的实现只是为了大便和咯咯笑,绝对不是我通常会做的事情,只是学习)
【解决方案2】:

我读过很多人说不要在返回时继续前进。据我所知,这是因为使用复制省略,在案例 get1 上,编译器不会调用构造函数 + 移动构造函数,而只会调用默认构造函数,而案例 get1bad 会强制编译器调用构造函数 + 移动。

如果return 语句的操作数只是一个局部变量的名称,那么std::move 基本上是隐式应用的。所以充其量return std::move(local_var); 是多余的。这是return 的特殊规则。它不适用于其他地方。

然而,使用return std::move(local_var); 使得强制复制省略规则不再适用,这就是为什么它不仅是多余的,而且比return local_var; 更糟糕。


我的问题是关于变量不是本地的情况(get2 vs get3)。在这种情况下,无论如何都会在类中构造变量。在 get2 中,我认为实际上没有任何优化是可能的。在这种情况下,如果我并不真正关心确保 B 类具有有效的 A 对象,那么实际移动不是更好吗?不就是调用通常比复制构造函数便宜的移动构造函数吗?

在您的示例中,所有成员函数都是const 限定的。因此std::move(member_var) 的类型将是const A&&。移动构造函数采用A&&,而不是const A&&。因此不会发生任何移动,并且复制构造函数将用于get2get3 的返回值。

如果您删除const 限定符,那么return std::move(member_var); 在这种情况下是有意义的,并且允许移动构造而不是复制构造。在这两种情况下都不能复制/移动省略,因为变量不是函数的本地变量。


在调用成员函数后,您不太可能不关心member_var 的状态,因此这在实践中不太可能有意义。如果我完全可以使用&& 限定成员函数,那么它仅在类实例是右值时使用,这是我能想到的唯一一种在调用后不关心对象状态的情况到成员函数。

【讨论】:

  • 嗨,谢谢,这正是我想知道的,正在尝试实现像 std::future 这样的类,这很酷,它确实澄清了我的问题。
猜你喜欢
  • 2015-01-08
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
相关资源
最近更新 更多