2014-04-10 145 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&&