在How to: Write a Move Constructor页面上Microsoft 有一个关于如何编写移动构造函数的示例。它本质上是以下形式:
MyClass::MyClass(MyClass&& lhs)
{
*this = std::move(lhs);
}
我已经尝试过并且std::move
确实需要这里,但是为什么呢?我认为 move 所做的唯一一件事就是转换为T&&
. 但是lhs
已经是 typeMyClass&&
了,不是吗?
在How to: Write a Move Constructor页面上Microsoft 有一个关于如何编写移动构造函数的示例。它本质上是以下形式:
MyClass::MyClass(MyClass&& lhs)
{
*this = std::move(lhs);
}
我已经尝试过并且std::move
确实需要这里,但是为什么呢?我认为 move 所做的唯一一件事就是转换为T&&
. 但是lhs
已经是 typeMyClass&&
了,不是吗?
命名的右值引用是左值。未命名的右值引用是右值。这对于理解为什么在以下情况下需要 std::move 调用很重要:
foo&& r = foo(); foo f = std::move(r);
看看这个答案:https ://stackoverflow.com/a/5481588/1394283它解释得很好。
看看这个函数:
void foo(X&& x)
{
X anotherX = x;
// ...
}
有趣的问题是:X
的复制构造函数的哪个重载在 的主体中被调用foo
?这里,x
是一个声明为右值引用的变量。因此,期望它x
自己也应该像右值一样绑定,也就是说,
X(X&& rhs);
应该被调用是很合理的。
允许将移动语义默认应用于具有名称的事物,例如
X anotherX = x;
// x is still in scope!
这将是危险的混乱和容易出错,因为我们刚刚移动的东西,即我们刚刚窃取的东西,仍然可以在后续代码行中访问。但移动语义的全部意义在于仅将其应用于“无关紧要”的地方,即我们移动的东西在移动后立即死亡并消失。
这就是为什么右值引用的设计者选择了一个比这更微妙的解决方案:
被声明为右值引用的事物可以是左值或右值。区分标准是:如果它有名字,那么它就是一个左值。否则,它是一个右值。
来源:http ://thbecker.net/articles/rvalue_references/section_05.html