2014-04-10 149 views
3

我對繼承層次結構中的移動構造函數有疑問。在C++中的引物(斯坦利李普曼)中提到,在一個繼承層次結構中的轉移構造函數將像這樣被定義:將繼承層次結構中的構造函數移動

class Base { /* Default Copy control and move constructor */ }; 

class D : public Base { 
public: 
    D(const D& d) : Base(d) {/*initializers for members of D */} //This is ok 
    D(D&& d): Base(std::move(d)) {/*initializers for members of D */} 
}; 

在移動構造函數,我試圖消除的std ::移動,同時調用由於基座移動的構造'd'是一個右值引用。

D(D&& d): Base(d) {/*initializers for members of D */} 

但是,這最終調用基類複製構造函數而不是移動構造函數。

爲了理解爲什麼std :: move是必需的,我搜索了這個論壇以查看以前的討論,並且我發現了幾個回覆,它們表示儘管'd'是右值引用,但在派生類的移動構造函數中它仍然一個左值。因此,我們需要調用std :: move來確保調用基類移動構造函數。我理解這一部分。

但是從C++ Primer中,我明白一旦調用了std :: move,我們就不應該在此之後使用該對象。在調用std :: move的表達式結束之後,該對象將保持有效的狀態以進行銷燬,但是它所保存的值可能沒有意義。

所以,當我們調用std :: move來委託給基類的移動構造函數時,當我們回到派生類的移動構造函數的主體時,對象會如何保持有意義的狀態。

換句話說:

D(D&& d): Base(std::move(d)) { 
    // Would 'd' be in a meaningful state here? 
    // After std::move(d), can I still use 'd' here? 
} 

我也明白,Base類將只是移動單獨與基類成員和派生類成員將不會被改變。但是,這是一個例外,在std :: move之後,對象的基礎部分將處於有效狀態,並且派生部分仍然處於有意義的狀態。請幫我理解這一點。

+0

如果我不在派生體中訪問d,那麼我將如何移動派生成員? – Madhusudhan

+0

複製交換成語(我沒有添加複製構造函數或賦值運算符):https://ideone.com/HpotCN它只是顯示移動如何與分層類一起工作。移動不會「毀滅」對象,直到移動完成(或直到它超出範圍)。它只是做一個有效的交換或其內部的透明副本。由於該對象實際上並未「移動」,因此仍然可以訪問其尚未觸及的其他成員。只有當移動完成時,另一個對象纔會被銷燬。至少我是這麼看的。 – Brandon

+0

@CantChooseUsernames - 我不明白你爲什麼使用std :: forward。我還沒有遇到std :: forward,並且我正在閱讀的這本書提到了std :: move在這裏使用。對不起我的無知。我是一個初學者,逐一閱讀各章。在你的代碼中,如果我用std :: move替換std :: forward,那麼swap(other,* this)仍然有效嗎?我在問這個,因爲這本書提到std :: move之後移動的對象不應該被使用。 – Madhusudhan

回答

3
class Base 
{ 
    // data members... 
public: 
    Base(Base&& other) = default; 
}; 

class Derived 
{ 
    // data members... 
public: 
    Derived(Derived&& other) : Base(std::move(other)) { ... } 
}; 

Derived轉移構造施放other使用std::move右值,然後將結果傳遞給所述移動Base構造,它涉及到隱式轉換從Derived&&Base&&

Base移動構造函數來偷的other基類成員的膽量,但不能觸及派生類成員的膽量,因爲它只能看到一個Base&&