std::move 操作在 c++11 中的行为
Behaviour of std::move operation in c++11
#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 assignedn"; return *this; }
A& operator=(A&& other) {
s = std::move(other.s);
std::cout << "move assignedn";`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 temporaryn";
a1 = f(A()); // move-assignment from rvalue temporary
std::cout << "Trying to move-assign A from xvaluen";
a2 = std::move(a1); // move-assignment from xvalue
std::cout << "Trying to move-assign Bn";
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 Cn";
C c1, c2;
c2 = std::move(c1); // calls the copy assignment operator
std::cout << "Trying to move-assign Dn";
D d1, d2;
// d2 = std::move(d1);
}
执行语句a2 = std::move(a1)
时,行为不同于执行语句b2 = std::move(b1)
。在下面的语句中,b1.s
在移动操作后不会变为空,而a1.s
在移动操作后变为空。
谁能说出那里到底发生了什么?
关于 C++11 和右值引用的一个巨大(且持续)误解是std::move
对对象(或该顺序上的某物)执行某些操作。
其实不然。 std::move
实际上只是将其参数强制转换为 rvalue 引用类型并返回该类型。对对象执行的任何操作都发生在移动构造函数、移动赋值运算符(等)中,基于调用采用右值引用的版本(而不是采用值或左值引用的版本)的事实。
就你问的具体问题而言,至少根据你代码中的注释,你似乎有一些误解。关于a2=std::move(a1);
的评论说您正在执行"从x值移动分配"。那是。。。充其量是误导。x值是立即被Xpire的值。这几乎是函数的返回值:
Foo &&bar() {
Foo f;
// ...
return f;
}
在这种情况下,bar()
是一个xvalue
,因为bar
返回对对象的右值引用,该对象在函数完成执行时过期(超出范围)。
就您提出的具体问题而言,我怀疑这主要归结为您的标准库是否(如果是,确切地如何)实现std::string
的移动构造函数的问题。例如,当使用g++(4.9.1)时,我得到的结果与您相同 - b1.s
在用作移动源之前和之后都包含test
。另一方面,如果我使用 MS VC++ 14 CTP,我会在移动前获得b1.s="test"
,在移动后b1.s=""
。虽然我还没有测试过它,但我希望 Clang 的结果是一样的。简而言之,看起来 gcc 的标准库并没有真正实现std::string
move
赋值/构造(然而——至少从 v 4.9 开始——我还没有看过 5.0)。
通常移动赋值是作为std::string
上的交换实现的,那么为什么字符串要变成空,因为它总是用"test"
初始化?
你在哪里看到a1.s
变得空,因为它没有印刷品?
我在这里没有看到任何奇怪的行为。两者的处理方式相同。
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 重载操作程序时出错>>用于类中的字符串 memebr
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- Usages of std::move
- 在C++中对T*类型执行std::move的意外行为
- 对字符串进行位操作
- 关于std::move的使用,是否有编译警告
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 我可以在 C++ 中的函数体之外进行操作吗?
- MPI突然停止了对多个核心的操作
- 通过实例理解std::move及其目的
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 对字符数组中的元素执行逐位操作
- 如何在directx/c++中进行平移/缩放操作
- 逐位操作的隐式类型转换
- 对std::move(x)执行一些操作
- std::move 操作在 c++11 中的行为
- 使用std::move在unique_ptr上对c++ 1y中模板化基类派生的类型进行操作
- 为什么不为定义了析构函数的类合成move操作呢?