我正在玩移动构造器和移动作业,我偶然发现了这个问题。第一个代码:
#include <iostream>
#include <utility>
class Foo {
public:
Foo() {}
Foo(Foo&& other) {
value = std::move(other.value);
other.value = 1; //since it's int!
}
int value;
private:
Foo(const Foo& other);
};
void Bar(Foo&& x) {
std::cout << "# " << x.value << std::endl;
}
int main() {
Foo foo;
foo.value = 5;
Bar(std::move(foo));
std::cout << foo.value << std::endl;
return 0;
}
在我看来,当我使用时:
Bar(std::move(foo));
程序应该将foo对象“移动”到使用Bar函数中的move构造函数创建的临时对象。这样做会使foo对象的值等于零。不幸的是它接触Bar函数中的对象作为参数是某种参考,因为它不会“移动”原始值,但使用Bar的参数我可以改变它。
有人会介意我在控制台看到我为什么会这样做:
#5
5
而不是
#5
0 //this should be done by move constructor?
答案 0 :(得分:18)
右值引用确实是(惊讶:)一个引用。
你可以从中移动,但std::move
不移动。
所以,如果你不从它移动,你实际上将操作rvalue对象(通过右值参考)。
通常的模式是
void foo(X&& x)
{
X mine(std::move(x));
// x will not be affected anymore
}
然而,当你这样做时
void foo(X&& x)
{
x.stuff();
x.setBooDitty(42);
}
有效地,X&amp;&amp;只是作为一个传统的参考
答案 1 :(得分:7)
当你写value = std::move(other.value);
时,你应该明白std::move
不会移动任何东西。它只是将其参数转换为右值参考,然后,如果左侧有一个移动构造函数/赋值运算符,左侧将处理它(以及如何实际移动对象)。对于普通旧类型(POD),std::move
并没有真正做任何事情,因此旧值保持不变。你不是&#34;身体&#34;移动任何东西。
答案 2 :(得分:2)
比较这两个函数:
void Bar(Foo&& x) {
std::cout << "# " << x.value << std::endl;
}
VS
void Bar(Foo&& x) {
std::cout << "# " << x.value << std::endl;
Foo y=std::move(x);
}
两者都采用右值引用,但只有第二个引用了移动构造函数。因此,第一个的输出是
# 5
5
而第二个的输出 - 因为foo
的值被改变 - 是:
# 5
1
编辑:这是我前段时间提出的一个问题。我的错误是假设rvalue引用的创建直接调用了移动构造函数的调用。但是,如前所述,std::move
在运行时没有做任何事情,它只是将类型更改为rvalue-reference。移动构造函数仅在您移动时才会调用&#34;你的左值引用如上所述另一个对象。
答案 3 :(得分:1)
Bar函数应不引用&&
(此语法仅在移动构造函数声明/定义中有效):
void Bar(Foo x) { ... } // not "Foo&& x"
在函数栏中调用临时参数对象的移动构造函数:
Bar( std::move( x ) );
要调用复制构造函数:
Bar( x );