Why explicit call of base move constructor actuall

2020-06-25 04:43发布

问题:

I'm trying to call the base class move ctor explicitly through derived class move ctor but, surprise!, that actually calls the base class copy ctor NOT the base class move ctor.

I'm using std::move() function on an object to be sure that the derived move ctor is being invoked!

The code:

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;
}

PROGRAM OUTPUT:

base copy ctor

derived move ctor

As you see, the base class move ctor is being forgotten, so how do I call it?

回答1:

In the context of your Derived class the parameter rhs clearly has a name. Thus, it must be an lvalue, it can't be an rvalue. However, the T&& only binds to rvalues. If you want to call the base class's move constructor you need to use code like this:

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

This will call the move constructor of Base and move the Base portion of rhs. Since Base doesn't know anything about the Derived members, the Base move constructor won't move anything added by Derived.



回答2:

A constructor, or any other function or method, with && in its signature will only be eligible to be selected by the compiler if both these conditions hold:

  • The datatype of the expression you are passing in is T&& or T. - i.e. T& won't be accepted
  • and it actually has to be an rvalue - e.g. returned (by value T or by T&&) from a function.

move(rhs) satisfies both of these conditions. rhs is of the right type, but it actually has to be returned from a function (such as move) before it can be considered eligible to be passed into a function that requires an &&.



回答3:

If the base class move constructor were used, then the derived constructor could access a moved-from object. That's dangerous, so it won't happen unless you explicitly tell the compiler that you're done using the object and it's safe to move.