Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move constructors in inheritance hierarchy

Tags:

c++

c++11

I have a doubt related to Move constructors in Inheritance hierarchy. In C++ Primer (Stanley Lippman) it is mentioned that the move constructor in an inheritance hierarchy would be defined like this:

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

In the move constructor, I tried removing std::move while calling the base move constructor since 'd' is a rvalue reference.

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

But this ended up calling the base class copy constructor instead of the move constructor.

To understand why std::move is required, I searched this forum to see previous discussions and I found out a few replies which said that though 'd' is a rvalue reference, within the derived class's move constructor it is still a lvalue. Hence we need to call std::move on it to ensure that base class move constructor is called. I understood this part.

But from C++ Primer, I understand that once std::move is called we should not use the object at all after that. After the expression in which std::move is called ends, the object will remain in a valid state for destruction but the values it holds may not be meaningful.

So when we call std::move to delegate to the base class's move constructor how then would the object remain in a meaningful state when we come back to the body of the derived class's move constructor.

In other words:

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

I do understand that the Base class would just move the members related to the base class alone and that the derived class members won't be touched. But is this an exception where after std::move the base part of the object would be in a valid to be destructed state and the derived part would still be in a meaningful state. Please help me understand this.

like image 816
MS Srikkanth Avatar asked Apr 10 '14 01:04

MS Srikkanth


1 Answers

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

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

The Derived move constructor casts other to an rvalue using std::move, then passes the result to the Base move constructor, which involves an implicit cast from Derived&& to Base&&.

The Base move constructor might steal the guts of the base class members of other, but it can't touch the guts of the derived class members because it only sees a Base&&.

like image 88
Oktalist Avatar answered Oct 18 '22 19:10

Oktalist