2013-11-21 24 views
2

類來進行測試:爲什麼不能自動替換此副本?

#include <iostream> 
#include <string> 

struct inner 
{ 
     std::string value; 

     inner() : value("test") { 
       std::cerr << "inner default construct\n"; 
     } 
     inner(inner &&mv) : value(std::move(mv.value)) { 
       std::cerr << "inner move construct\n"; 
     } 
     inner(inner const &copy) : value(copy.value) { 
       std::cerr << "inner copy construct\n"; 
     } 
}; 

struct outer 
{ 
     inner value; 
     outer() {} 
     outer(inner v) 
       : value(v) 
     {} 
}; 

移動語義的一個簡單的測試做什麼,我預計:

inner mover(inner x) 
{ 
     return x; 
} 
int main() 
{ 
     inner i; 
     auto q = mover(std::move(i)); 
     return 0; 
} 

...它輸出:

內默認的構造

內動構造

內移動構建

但這主要做一些事情我沒有想到:

int main() 
{ 
     inner i; 
     outer o(std::move(i)); 
     return 0; 
} 

內默認的構造

內移動構建

內拷貝構造

我期待複製是另一個舉動,因爲它在第一個主要。爲什麼優化在第一種情況下可用,而在第二種情況下不可用?

我意識到我可以明確地調用std :: move在outer(inner v)構造函數....但爲什麼這是必需的?爲什麼編譯器不能做隱式的移動?

回答

2

我在C++ 11個右值語義學對專家,但outer沒有接受一個inner右值引用一個構造函數,所以編譯器別無選擇,只能作出inner拷貝自outer構造函數的輸入參數是一個左值,因此必須在初始化outer::v成員時調用inner拷貝構造函數而不是移動構造函數。

你不要在mover()例如拷貝的原因可能是由於Return Value Optimization,從而無需進行任何拷貝的需要,如果輸入inner實例可以直接移動到目標q變量,從而調用inner移動構造函數而不是複製構造函數。

+0

你可以移動到一個參數值 – aaronman

+0

右,當輸入的內部實例被創建並傳遞給外部構造函數之前,它將解釋內部構造信息。但在該構造函數內部,'inner v'參數是一個左值,而不是右值。由於左值不能綁定到右值引用,所以'outer :: v'成員不能通過'inner'移動構造函數初始化,只能使用複製構造函數,因此是'inner copy construct'消息。 –

3

您需要在初始化程序列表中說: value(std::move(v))

+0

我知道會工作,我的問題是爲什麼這是必需的?我將編輯問題更清楚。 – SoapBox

+1

@SoapBox:我不明白這個問題 - 沒有'move','v'是一個左值,你不能得到移動構造函數。 –

+0

在從函數返回的情況下(在我的第一個示例中),「x」是否爲l值?爲什麼可以移動那個,但構造函數中的那個不能? – SoapBox

相關問題