我测试了这段代码,看看编译器会自动将临时对象转移到变量而不需要移动构造函数。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"Hi from default\n";
}
A(A && obj)
{
cout<<"Hi from move\n";
}
};
A getA()
{
A obj;
cout<<"from getA\n";
return obj;
}
int main()
{
A b(getA());
return 0;
}
此代码打印“Hi from default from getA”而不是假定的“Hi from move”
在优化方面,它很棒。但是,如何在不添加副本的情况下强制调用移动构造函数? (如果我想要临时对象的特定行为)
补充问题:我虽然如果我没有编写移动构造函数,每次我将rvalue分配给左值时都会有一个副本(就像在A b(getA());
行的代码中那样)。既然情况并非如此,并且编译器似乎表现良好,那么何时实现移动语义真的很有用呢?
答案 0 :(得分:3)
在优化方面,它很棒。但是,如何在不添加副本的情况下强制调用移动构造函数? (如果我想要临时对象的特定行为)
通常,这需要禁用优化标志才能获得此行为。对于gcc和clang,您可以使用-fno-elide-constructors
来关闭复制elison。对于MSVS,它不会在调试模式下执行(优化已关闭),但我不确定它们是否具有此特定标志
您还可以在return语句中调用std::move
,这将禁用elision并强制编译器生成临时文件并从中移动。
return std::move(obj);
那就是说,你应该想要RVO / NRVO。如果你可以提供帮助,你甚至不应该想要临时创建,因为减少工作意味着你可以在同一时间完成更多的工作。为此,C ++ 17引入了guaranteed copy elision来阻止那些临时存在。
这并不意味着你不应该写一个移动构造函数(如果你遵循rule of zero那么你就不会写一个并且只使用提供的编译器)。有时候编译器不能忽略一个临时值,或者你想移动一个左值,所以它仍然是一个有用的东西。