c++ - 如果右值引用确实需要 std::move,我们应该什么时候声明它们?

标签 c++ move-semantics rvalue

正如许多其他帖子所解释的那样,将一个变量声明为右值引用不能保证它将调用 move 赋值运算符,仅使用 std::move (即也就是说,转换为相同的右值引用)就可以了。例如:

struct A
{
    A& operator=(A&& l_other) { std::cout << "move" << std::endl; }
    A& operator=(A&  l_other) { std::cout << "copy" << std::endl; }
};

A a;

// does not print anything, compiler does nothing here!
A&& b = std::move(a);

// prints "copy", not "move"
a = b;

// prints "move", but needs std::move()
a = std::move(b);

似乎将 b 定义为 A&& 在那一刻不会 move 任何东西。之后,a = b 不会自动 move b,即使右侧部分被定义为 A&&,正如其他帖子所解释的那样。我们需要显式调用 std::move(b) 来 move b

我的问题是,将变量定义为 A&& 有什么用处?我可以完美地将其定义为 A& 并将其精确 move 到一样。

最佳答案

My question is, what's the utility of defining a variable as A&&? I could perfectly define it as A& and move it exactly the same.

如果将命名变量传递到函数中并像这样进行修改而不发出警告,这是非常令人不快的,并且可能会导致令人不快的调试 session 。

当您使用右值引用时,类型系统会强制执行有用的保证。要么引用绑定(bind)到一个右值,所以修改它不会违反任何人的假设(无论如何它很快就消失了)。或者您已获得明确许可搬出。调用上下文不能意外地授予您修改左值的权限,它必须通过显式强制转换 (std::move) 来执行此操作。

显式优于隐式。让右值引用以它们的方式与类型系统交互有助于确保 move 不会使对象处于意外状态。看一眼调用上下文就会发现,传递到函数中的变量可能处于未知状态,因为它显式地包含对 std::move 的调用。

这就是右值引用的好处。

关于c++ - 如果右值引用确实需要 std::move,我们应该什么时候声明它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58854278/

相关文章:

c++ - 为什么这个imapclient g++编译会出错

c++ - opencv 中的视觉里程计(可能使用 RGBD)

c++ - move 语义和 std::future

c++ - 转换运算符的 move 语义

c++ - c++03 与 11 中的返回值

c++ - Apache Kafka 可以与 C++ 一起使用吗?

c++ - 如何使用初始化列表初始化数组元素?

c++ - 对象返回时是否保证被 move ?

c++ - 常量引用和左值

c++ - 编译为 C++ 但不是 C(错误 : lvalue required as unary '&' operand)