描述:
在C 11 中使用移動語義時,這是可能的遇到移動建構函式被意外跳過而轉而使用預設建構函式的情況。本文探討了這個問題,檢視了根本原因,並提供了解決方案。
問題:
考慮以下帶有輸出訊息的建構函式的類別X:
<code class="cpp">class X { public: explicit X(char* c) { cout << "ctor" << endl; init(c); } X(X& lv) { cout << "copy" << endl; init(lv.c_); } X(X&& rv) { cout << "move" << endl; c_ = rv.c_; rv.c_ = nullptr; } const char* c() { return c_; } private: void init(char *c) { c_ = new char[strlen(c)+1]; strcpy(c_, c); } char* c_; };</code>
在下面提供的範例用法中,我們建立了三個物件:
<code class="cpp">X x("test"); cout << x.c() << endl; X y(x); cout << y.c() << endl; X z( X("test") ); cout << z.c() << endl;</code>
但是,預期輸出並未顯示為z 呼叫的移動建構函數,而是使用預設建構函數。
標準一致性:
依據 C 11 標準 (§12.8.32),只要可能,移動語意應優先於複製語意。因此,在這種情況下,確實應該為 z 呼叫移動構造函數。
行為說明:
觀察到的行為是由於名為 copy elision。 C 11 允許編譯器在某些情況下省略複製/移動物件以提高效能。其中一種情況是,臨時物件將被複製/移動到具有相同 cv-unqualified 類型的物件。
解:強制移動建構函式為呼叫後,我們可以使用std::move() 來明確指示應該要移動:
<code class="cpp">X z( std::move(X("test")) );</code>透過此修改,將產生預期的輸出,確認移動構造函數的參與。
以上是為什麼使用臨時物件初始化另一個物件時沒有呼叫 C 11 移動建構函式?的詳細內容。更多資訊請關注PHP中文網其他相關文章!