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.
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&&
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With