复制省略并移动语义不按预期工作

时间:2015-07-20 13:34:08

标签: c++ optimization

我制定了一个程序来评估这样做之间的性能差异:

func3(func2(func1()));

vs this:

retval1 = func1();
retval2 = func2(retval1);
func3(retval2);

我更喜欢后者的可读性和易于调试,我想知道编译器(MSVC 12.0)是否会优化发布版本中的中间对象。我的测试程序是这样的:

#include <iostream>

using namespace std;

struct Indicator {
    Indicator() {cout << "Default constructor" << endl;}
    Indicator(const Indicator& other) {cout << "Copy constructor" << endl;}
    const Indicator& operator=(const Indicator& other) {cout << "Assignment operator" << endl;}
    ~Indicator() {cout << "Destructor" << endl;}
};

Indicator func1()
{return Indicator();}

Indicator func2(Indicator&& i)
{return std::move(i);}

Indicator func3(Indicator&& i)
{return std::move(i);}

int main() {
    Indicator i = func3(func2(func1()));
    cout << &i << endl;
    return 0;
}

我很惊讶地发现,即使使用-O2,仍然会创建三个Indicator实例:

Default constructor
Copy constructor
Copy constructor
Destructor
Destructor
00000000002EFC70
Destructor
Press <RETURN> to close this window...

这与我对移动语义的理解相冲突,即在这种情况下应该只创建一个Indicator实例。我还认为编译器应该能够使用NRVO进行链式函数调用。有人可以向我解释这里发生了什么吗?

1 个答案:

答案 0 :(得分:6)

在定义复制构造函数和复制赋值运算符时基于rule of 5,禁用了编译器生成的移动构造函数并移动赋值运算符。

如果你定义了移动构造函数,你将得到你期望的输出。

Indicator(Indicator&& other) {cout << "Move constructor" << endl;}
Indicator& operator=(Indicator&& other) {cout << "Move assignment operator" << endl;}

Working demo