2015-07-20 33 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