如何强制调用移动构造函数,为什么要这样做?

时间:2017-04-21 12:21:23

标签: c++ move-semantics temporary-objects copy-elision

我测试了这段代码,看看编译器会自动将临时对象转移到变量而不需要移动构造函数。

#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());行的代码中那样)。既然情况并非如此,并且编译器似乎表现良好,那么何时实现移动语义真的很有用呢?

1 个答案:

答案 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那么你就不会写一个并且只使用提供的编译器)。有时候编译器不能忽略一个临时值,或者你想移动一个左值,所以它仍然是一个有用的东西。