2012-08-14 76 views
6

我用下面的代碼測試複製省略:爲什麼copy elision不能使用std :: move?

class foo 
{ 
public: 
    foo() {cout<<"ctor"<<endl;}; 
    foo(const foo &rhs) {cout<<"copy ctor"<<endl;} 
}; 

int g(foo a) 
{ 
    return 0; 
} 

int main() 
{ 
    foo a; 
    g(std::move(a)); 
    return 0; 
} 

我預計只有默認的構造函數被調用,因爲g()參數是一個右值和副本將被省略。但結果顯示默認構造函數和複製構造函數都被調用。爲什麼?

如果我將函數調用更改爲g(foo()),副本將被忽略。 foo()std::move(a)的退貨類型有什麼區別?我怎樣才能使編譯器elide副本左值?

+4

你不能。'g'按值取其參數,所以編譯器必須確保傳遞的對象不同於從調用範圍可訪問的任何對象。如果傳遞的對象是左值,則不會暫時消除並且不能消除副本。 – 2012-08-14 06:07:11

+1

你期望有多少析構函數調用? ;) – curiousguy 2012-08-14 06:29:42

+0

您可能需要[read up](http://stackoverflow.com/a/11540204/252000)瞭解'std :: move'實際執行的操作。 – fredoverflow 2012-08-14 11:25:23

回答

6

複製elision for只能發生在幾個特定的​​情況下,其中最常見的是複製臨時(其他人正在返回本地,並拋出/捕捉異常)。你的代碼沒有臨時產生,所以沒有拷貝被消除。

拷貝構造函數被調用,因爲foo沒有一個移動構造函數(move構造函數都不會隱與顯式的拷貝構造函數的類產生的),所以std::move(a)foo(const foo &rhs)構造函數(這是用來構造函數參數)相匹配。

左值的副本可在下列情況下被省略(雖然沒有辦法編譯器執行省音):

foo fn() { 
    foo localAutomaticVariable; 
    return localAutomaticVariable; //Copy to construct return value may be elided 
} 

int main() { 
    try { 
     foo localVariable; 
     throw localVariable; //The copy to construct the exception may be elided 
    } 
    catch(...) {} 
} 

如果你想傳遞功能時避免拷貝參數,你可以使用一個移動構造函數pilfers給它的對象的資源:

class bar { 
public: 
    bar() {cout<<"ctor"<<endl;}; 
    bar(const bar &rhs) {cout<<"copy ctor"<<endl;} 
    bar(bar &&rhs) {cout<<"move ctor"<<endl;} 
}; 

void fn(bar a) 
{ 
} 
//Prints: 
//"ctor" 
//"move ctor" 
int main() 
{ 
    bar b; 
    f(std::move(b)); 
} 

而且,只要複製省略是允許的,但不會發生,此舉構造函數將被使用,如果它是availab樂。

+0

+1,值得注意的是默認情況下沒有移動構造函數,所以參數的構造必須回退到拷貝構造函數,即使是r值也是如此。 – KillianDS 2012-08-14 07:45:16

4

需要聲明g爲:

int g(foo && a) //accept argument as rvalue reference 
{ 
    return 0; 
} 

現在,它可以接受右值引用的參數。

就您而言,即使表達式std::move(a)產生右值,它也不會綁定到接受參數的值爲的參數。接收端也必須是rvalue-reference

如果是g(foo()),則copy-elision由編譯器執行,這是一種優化。 這不是語言要求[until C++17]。如果您想要:您可以禁用此優化:然後g(foo())g(std::move(a))的行爲與預期完全相同。

但是,如果你改變g正如我上面所說,電話g(foo())不會讓一個副本,因爲它是由語言的要求不使副本& &。它不再是編譯器優化。

+5

我想你錯過了這個問題的重點。這個簽名將不會出現副本,只是因爲不會複製。 – hvd 2012-08-14 06:05:34

+0

@hvd:我不明白你的評論。這樣做的基礎是什麼:*「沒有簽名的副本,只因爲不會複製」*? – Nawaz 2012-08-14 06:08:13

+2

有人可能會爭辯說,copy-ellision是由編譯器執行的優化(儘管我不確定這是否正確)。在這種情況下,您的解決方案不是複製 - 省略。 – 2012-08-14 06:12:52

相關問題