#include <string>
#include <iostream>
#include <utility>
struct A {
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!\n"; }
A(A&& o) : s(std::move(o.s)) {}
A& operator=(const A&) { std::cout << "copy assigned\n"; return *this; }
A& operator=(A&& other) {
s = std::move(other.s);
std::cout << "move assigned\n";`enter code here`
return *this;
}
};
A f(A a) { return a; }
struct B : A {
std::string s2;
int n;
// implicit move assignment operator B& B::operator=(B&&)
// calls A's move assignment operator
// calls s2's move assignment operator
// and makes a bitwise copy of n
};
struct C : B {
~C() {}; // destructor prevents implicit move assignment
};
struct D : B {
D() {}
~D() {}; // destructor would prevent implicit move assignment
//D& operator=(D&&) = default; // force a move assignment anyway
};
int main()
{
A a1, a2;
std::cout << "Trying to move-assign A from rvalue temporary\n";
a1 = f(A()); // move-assignment from rvalue temporary
std::cout << "Trying to move-assign A from xvalue\n";
a2 = std::move(a1); // move-assignment from xvalue
std::cout << "Trying to move-assign B\n";
B b1, b2;
std::cout << "Before move, b1.s = \"" << b1.s << "\"\n";
b2 = std::move(b1); // calls implicit move assignment
std::cout << "After move, b1.s = \"" << b1.s << "\"\n";
std::cout << "Trying to move-assign C\n";
C c1, c2;
c2 = std::move(c1); // calls the copy assignment operator
std::cout << "Trying to move-assign D\n";
D d1, d2;
// d2 = std::move(d1);
}
执行a2 = std::move(a1)
语句时,行为与执行语句b2 = std::move(b1)
不同。在下面的语句中,b1.s
在移动操作后不会变空,而a1.s
在移动操作后变为空。
谁能告诉那里到底发生了什么?
答案 0 :(得分:2)
关于C ++ 11和rvalue引用的一个很好的(和常量的)误解是std::move
对某个对象(或该顺序上的某些东西)做了某些事情。
没有。 std::move
实际上只是将其参数转换为rvalue引用类型并返回该参数。对对象所做的任何事情都发生在移动构造函数中,移动赋值运算符(等等)基于调用带有右值引用的版本的事实(而不是采用值或左值引用的版本)。
就您提出的具体问题而言,至少根据代码中的注释,您似乎有一些误解。对a2=std::move(a1);
的评论说你正在“从xvalue移动分配”。那......充其量只是误导。 xvalue是一个立即进行eXpire的值。这几乎是函数的返回值:
Foo &&bar() {
Foo f;
// ...
return f;
}
在这种情况下,bar()
是xvalue
因为bar
返回对一个对象的rvalue引用,该对象在函数完成执行时到期(超出范围)。
就你提出的具体问题而言,我怀疑它主要归结为一个问题,即你的标准库是否(以及如果确实如何)实现了std::string
的移动构造函数。例如,当使用g ++(4.9.1)时,我得到了相同的结果 - b1.s
在用作移动源之前和之后都包含test
。另一方面,如果我使用MS VC ++ 14 CTP,移动前会得到b1.s="test"
,移动后会得b1.s=""
。虽然我没有测试过,但我希望Clang的结果是一样的。简而言之,看起来gcc的标准库并没有真正为move
实现std::string
赋值/构造(至少从v 4.9开始 - 我还没有看过5.0)。
答案 1 :(得分:1)
通常移动分配是作为std::string
上的交换实现的,那么为什么字符串变为空,因为它总是用"test"
初始化?
在哪里看到a1.s
因为没有打印而变空?
我没有看到任何奇怪的行为here。两者都以同样的方式对待。