ged*_*ial 23 c++ move move-constructor move-semantics c++11
看看这段代码:
class Foo
{
public:
string name;
Foo(string n) : name{n}
{
cout << "CTOR (" << name << ")" << endl;
}
Foo(Foo&& moved)
{
cout << "MOVE CTOR (moving " << moved.name << " into -> " << name << ")" << endl;
name = moved.name + " ###";
}
~Foo()
{
cout << "DTOR of " << name << endl;
}
};
Foo f()
{
return Foo("Hello");
}
int main()
{
Foo myObject = f();
cout << endl << endl;
cout << "NOW myObject IS EQUAL TO: " << myObject.name;
cout << endl << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
[1] CTOR(你好)
[2] MOVE CTOR(将Hello移入 - >)
[3]你好的DTOR
[4] MOVE CTOR(将Hello ###移动到 - >)
[5] Hello ###的DTOR
[6] 现在两个是等于:你好### ###
[7]你好的DTOR ### ###
重要说明:我已禁用复制省略优化-fno-elide-constructors用于测试目的.
函数f()构造一个临时的[1]并返回它,调用move构造函数将资源从那个临时"移动"到myObject [2] (另外,它添加了3个#符号).
最终,临时被破坏[3].
我现在希望myObject完全构造,其name属性为Hello ###.
相反,移动构造函数被称为AGAIN,所以我留下了Hello ### ###
Tar*_*ama 25
两个移动构造函数调用是:
Foo("Hello")值移动到返回值中.f()调用返回的临时值移动到myObject.如果使用braced-init-list构造返回值,则只有一个移动构造:
Foo f()
{
return {"Hello"};
}
Run Code Online (Sandbox Code Playgroud)
这输出:
CTOR (Hello)
MOVE CTOR (moving Hello into -> )
DTOR of Hello
NOW myObject IS EQUAL TO: Hello ###
DTOR of Hello ###
Run Code Online (Sandbox Code Playgroud)
Sme*_*eey 10
因为您关闭了复制省略,所以首先创建对象f(),然后将其移动到返回值占位符中f().此时,f本地副本被销毁.接下来,返回对象被移入myObject并被销毁.终于myObject被摧毁了.
如果你没有禁用复制省略,你会看到你期望的序列.
更新:在下面的评论中解决问题,这是 - 给定这样的函数的定义:
Foo f()
{
Foo localObject("Hello");
return localObject;
}
Run Code Online (Sandbox Code Playgroud)
为什么在创建返回值对象时禁用了复制省略来调用移动构造函数?毕竟,上面的localObject是一个左值.
答案是编译器在这些情况下有义务将本地对象视为右值,因此有效地隐式生成代码return std::move(localObject).需要它执行此操作的规则在标准[class.copy/32]中(突出显示相关部分):
当满足复制/移动操作的省略标准时,但不满足异常声明,并且要复制的对象由左值指定,或者当返回语句中的表达式是(可能带有括号的)id-时表达式,用于在最内层封闭函数或lambda-expression 的body或parameter-declaration-clause中声明的具有自动存储持续时间的对象,首先执行重载决策以选择复制的构造函数,就像对象由rvalue指定一样.
...
[注意:无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数. - 结束说明]
| 归档时间: |
|
| 查看次数: |
1567 次 |
| 最近记录: |