2012-01-17 133 views
3

我试图通过派生类移动ctor显式调用基类移动ctor但惊喜!,这实际上是调用基类复制ctor不是基类移动ctor。为什么基础移动构造函数的显式调用实际上调用基础构造函数?

我在对象上使用std::move()函数以确保派生的move ctor被调用!

代码:

class Base 
{ 
public: 
    Base(const Base& rhs){ cout << "base copy ctor" << endl; } 
    Base(Base&& rhs){ cout << "base move ctor" << endl; } 
}; 

class Derived : public Base 
{ 
public: 

    Derived(Derived&& rhs) : Base(rhs) { cout << "derived move ctor"; } 
    Derived(const Derived& rhs) : Base(rhs) { cout << "derived copy ctor" << endl; } 
}; 

int main() 
{ 
    Derived a; 
    Derived y = std::move(a); // invoke move ctor 
    cin.ignore(); 
    return 0; 
} 

程序输出:

基地拷贝构造函数

衍生举动男星

正如你看到的,基类移动男星正在被遗忘,所以我怎么称呼它?

回答

5

在您的Derived类的上下文中,参数rhs显然具有名称。因此,它必须是一个左值,它不能是一个右值。然而,T&&只绑定到右值。如果你想调用基类的构造函数的举动,你需要使用这样的代码:

Derived(Derived&& rhs): Base(std::move(rhs)) { std::cout << "derived move ctor"; } 

这将调用Base移动构造函数和移动的rhsBase部分。由于Base不知道Derived成员的任何信息,因此Base移动构造函数不会移动Derived添加的任何东西。

+0

以及如果我会在主函数中写这个:Derived y = Derived();也忘记了std :: move?我已经尝试过,在那种情况下,我没有任何程序输出,那么真正被称为什么? – codekiddy

+0

@codekiddy:在示例中,Derived y = Derived()概念上称为移动构造函数:右侧的对象不能被引用,即它不是左值。但是,移动构造可能被大多数编译器忽略:如果编译器可以直接在正确的位置构建临时对象,则可以不使用移动(或复制)构造,即使构造函数不会产生副作用, t被忽略(例如,从构造函数或析构函数中输出)。 –

+0

所以移动rhs的基础部分我被迫在派生的移动ctor中使用Base(std :: move(rhs)),有没有什么办法可以避免std :: move?多谢 – codekiddy

1

如果使用基类移动构造函数,则派生的构造函数可以访问移入的对象。这很危险,所以不会发生,除非你明确地告诉编译器你已经完成了使用该对象并且移动是安全的。

+0

对于移动构造函数来说,它只是非常危险而已。原因是在编写'Base(rhs)'时,'Base'的构造函数被左值调用,并且左值不会绑定右值引用:您必须明确地将左值看作右值。 –

+0

@DietmarKühl:它被分类为左值,因为它可以在以后访问。 –

+0

哦,你想避免术语左值和右值? ...因为这是两者之间的重要区别。 –

2

一个构造函数,或者任何其他函数或方法,并在它的签名&&只会有资格由编译器,如果这两个条件成立来选择:

  • 要传递的表达的数据类型是T&&T。 - 即T&将不被接受
  • 它实际上必须是一个右值 - 例如,从函数返回(值为TT&&)。

move(rhs)满足这两个条件。 rhs是正确的类型,但实际上它必须从函数返回(如move)才可以被认为有资格传递到需要&&的函数。

相关问题