2015-07-20 31 views
3

我做了一个程序来评估这样的性能差异:复制省略和移动语义不能按预期工作

func3(func2(func1())); 

VS这样的:

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; 
} 

我很惊讶地看到,即使-02,还有正在创建的Indicator三个实例:

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

与我的移动语义的理解这种矛盾,这就是说在这种情况下应该只创建一个Indicator实例。我还认为编译器应该能够将NRVO用于链式函数调用。有人可以向我解释这里发生了什么事吗?

回答

6

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

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

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

Working demo

+2

[(另见)(http://stackoverflow.com/questions/8283589) –

+1

这是值得大家注意的Visual C++ 12不会产生隐性转移构造的。 – stgatilov

+0

啊。好的我知道了。我刚刚习惯了遵守3的规则,现在我必须记得定义移动构造函数以及... – Carlton