4

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

#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”

在优化方面,它很棒。但是,如何在不添加副本的情况下强制调用移动构造函数?(如果我想要临时对象的特定行为)

补充问题:我认为,如果我没有编写移动构造函数,那么每次我将右值分配给左值时都会有一个副本(就像在该行的代码中一样A b(getA());)。既然情况并非如此,而且编译器似乎做得很好,那么实现移动语义什么时候真正有用?

4

1 回答 1

4

在优化方面,它很棒。但是,如何在不添加副本的情况下强制调用移动构造函数?(如果我想要临时对象的特定行为)

通常,这需要禁用优化标志才能获得此行为。对于 gcc 和 clang,您可以使用-fno-elide-constructors关闭复制 elison。对于 MSVS,它不会在调试模式下执行此操作(优化已关闭),但我不确定他们是否为此设置了特定标志

您还可以调用std::movereturn 语句,这将禁用省略并强制编译器生成临时并从中移动。

return std::move(obj);

也就是说,RVO/NRVO 是您应该想要的。如果您可以提供帮助,您甚至不应该创建临时文件,因为完成的工作更少意味着您可以同时完成更多的工作。为此,C++17 引入了保证复制省略,它甚至阻止了这些临时对象的存在。

这并不意味着你不应该写一个移动构造函数(如果你遵循零规则,那么你就不会写一个,而只是使用编译器提供的一个)。有时编译器可能无法忽略临时值,或者您想移动左值,所以它仍然是有用的东西。

于 2017-04-21T12:57:36.123 回答