2014-10-07 60 views
2

下面的代碼,在VS2013編譯,從未調用的std :: string的移動構造函數(通過設置斷點檢查,const的裁判拷貝構造函數,而不是調用。爲什麼下面的代碼不會調用std :: string的移動構造函數?

#include <iostream> 
#include <string> 
#include <stdlib.h> /* srand, rand */ 
#include <time.h> /* time */ 

struct foo 
{ 
    foo(std::string& str1, std::string& str2) : _str1(str1), _str2(str2) {} 

    ~foo() { std::cout << "Either \"" << _str1 << "\" or \"" << _str2 << "\" was returned." << std::endl; } 

    std::string& _str1; 
    std::string& _str2; 
}; 

std::string foobar() 
{ 
    std::string str1("Hello, World!"); 
    std::string str2("Goodbye, cruel World."); 
    foo f(str1, str2); 

    srand(time(NULL)); 

    return (rand() % 2) ? str1 : str2; 
} 

int main() 
{ 
    std::cout << "\"" << foobar() << "\" was actually returned." << std::endl; 

    return EXIT_SUCCESS; 
} 

我希望在foobar的return語句()以調用移動構造函數,因爲我返回一個本地(蘭德()是爲了防止NRVO),就像問題的回答,如Returning std::move of a local variable

這是我試圖添加另一個例子我的其他問題在這裏:https://softwareengineering.stackexchange.com/questions/258238/move-semantics-in-c-move-return-of-local-variables

+0

是否使用移動的構造函數,如果你刪除'foo'變量定義?我猜想編譯器足夠聰明,知道你已經參考了使得移動無效的字符串(再次,猜測)。 – uesp 2014-10-07 18:16:53

+0

不,它仍然使用複製構造函數,如果我這樣做。 – Bwmat 2014-10-07 18:18:53

+1

返回的「首先嚐試右值」僅適用於「如果複製elision條件已滿足或將滿足,除了源對象是函數參數」這一事實。在C++ 14中,它擴展到所有return語句直接命名本地對象的情況。 (見[這個答案](http://stackoverflow.com/questions/25875596/can-returning-a-local-variable-by-value-in-c11-14-result-in-the-return-value-b/25876175#25876175)從標準的完整報價。)您的條件表達式既不是。 – 2014-10-07 18:18:53

回答

5

C++ 11有一個特殊情況,當它是局部變量時可用於複製/移動省略,並用作函數的返回表達式:

C++ 11 12.8/31「複製和移動類對象」 :

在與類返回類型,當 表達式是一個非易失性自動對象的具有相同的CV(比 函數或catch子句參數之外)的名稱的功能的返回語句

- 不合格 類型作爲函數返回類型,複製/移動操作可以是 省略通過將自動對象直接構建到 函數的返回值

但是這種情況不適用於複製elision,因爲您擁有的return語句不是簡單的「非易失性自動對象的名稱」。

後來,標準提到

C++ 11 12.8/32「複製和移動類對象」:

當的複製操作的省音滿足準則或將是 遇到源對象爲函數參數 並且要複製的對象由左值指定的事實,則重載 分辨率爲拷貝選擇構造函數首先執行 就好像對象由右值指定一樣。如果超載分辨率 失敗,或者如果所選 構造函數的第一個參數的類型不是對象類型的右值引用(可能爲 cv-qualified),則將 對象視爲左值,重新執行重載解析。 [注意:無論是否發生複製刪除,都必須執行這個兩階段重載解析度 。它 確定如果不執行省略,則調用構造函數, 和選定的構造函數必須可訪問,即使調用 不成立。 - 結束註釋]

即使返回指定了左值,也可以使用移動操作。但是,這種特殊情況只適用於第一句話的條件,在您的示例return聲明的情況下不適用。

您可以強制問題:

return (rand() % 2) ? std::move(str1) : std::move(str2); 
+0

它會使用'if(rand()&2)return str1;否則返回str2;'? – 2014-10-07 19:09:35

+0

@GuilhermeBernal:是的,也可以。 – 2014-10-07 19:54:15

相關問題