2010-11-03 63 views
29

當您有一個帶有移動構造函數的派生對象並且基礎對象也具有移動語義時,從派生對象移動構造函數調用基礎對象移動構造函數的正確方法是什麼?在派生對象上移動構造函數

我第一次嘗試的最明顯的事情:

Derived(Derived&& rval) : Base(rval) 
{ } 

然而,這似乎最終調用基對象的拷貝構造函數。然後我試圖明確使用std::move這裏,像這樣:

Derived(Derived&& rval) : Base(std::move(rval)) 
{ } 

這個工作,但我很困惑爲什麼它是必要的。我以爲std::move只是返回一個右值引用。但是因爲在這個例子中rval已經是一個右值引用,所以調用std::move應該是多餘的。但如果我在這裏不使用std::move,它只是調用複製構造函數。那麼爲什麼需要撥打std::move

回答

29

rval不是一個Rvalue。它是移動構造函數體內的左值。這就是爲什麼我們必須明確調用std :: move。

請參閱this。在重要的一點是

注意上面的參數x是 作爲左值內部的 移動功能的處理,即使它被聲明爲右值引用 參數 。這就是爲什麼當 傳遞給基類時,需要 說move(x)而不是x。此 是 語義的一個關鍵安全功能,旨在防止 意外地從一些 命名變量中移動兩次。所有移動都只能從rvalues發生 ,或者使用std :: move等明確轉換 進行右移。如果 你有一個變量名稱,它 是一個左值。

+0

如果你提供一個參數輸入作爲常規左值(不使用std :: move(xx)),只需要添加一個記錄而不管移動構造函數如何,你將得到「不能綁定'Xyy'左值爲'Xyy &&'定義爲foo(Xyy && xyy) – 2017-03-23 19:51:29

0

你真的應該使用std :: forward(obj)而不是std :: move(obj)。向前將根據什麼obj返回適當的右值或左值,而移動將左值變爲右值。

+10

在這種情況下,你總是希望拋出一個右值 – 2011-02-01 20:02:01

+2

所以真正的意圖是正確地轉發,而不是改變傳入的內容。轉發()確實如此。也會讓你進入使用它調用所有基函數的習慣,不管傳入的是什麼。養成調用move()的習慣可能會產生很難追蹤的錯誤,如果你想要在一個函數上使用模板,該函數既可以作用於右值也可以作用左值,如果這個作用被錯誤地傳遞給一個左值的對象,它會讓它變成c繼續執行?只是玩惡魔提倡一點點 – jbreiding 2011-02-02 17:31:23

+1

@jbreiding我不明白任何這個......介意你的解釋與一些代碼示例時std ::移動將失敗,爲什麼std :: forward是首選和什麼時候使用哪一個? – aCuria 2012-03-10 16:25:13