When you have a derived object with a move constructor, and the base object also has move semantics, what is the proper way to call the base object move constructor from the derived object move constructor?
I tried the most obvious thing first:
Derived(Derived&& rval) : Base(rval) { }
However, this seems to end up calling the Base object's copy constructor. Then I tried explicitly using std::move
here, like this:
Derived(Derived&& rval) : Base(std::move(rval)) { }
This worked, but I'm confused why it's necessary. I thought std::move
merely returns an rvalue reference. But since in this example rval
is already an rvalue reference, the call to std::move
should be superfluous. But if I don't use std::move
here, it just calls the copy constructor. So why is the call to std::move
necessary?
Whenever the derived class's default constructor is called, the base class's default constructor is called automatically. To call the parameterized constructor of base class inside the parameterized constructor of sub class, we have to mention it explicitly.
It's faster because moving allows the source to be left in a invalid state, so you can steal it's resources. For example, if a object holds a pointer to a large block of allocated memory, a move can simply steal the pointer while a copy must allocate its own memory and copy the whole memory block.
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&. This topic builds upon the following C++ class, MemoryBlock , which manages a memory buffer.
If a copy constructor, copy-assignment operator, move constructor, move-assignment operator, or destructor is explicitly declared, then: No move constructor is automatically generated. No move-assignment operator is automatically generated.
rval
is not a Rvalue. It is an Lvalue inside the body of the move constructor. That's why we have to explicitly invoke std::move
.
Refer this. The important note is
Note above that the argument x is treated as an lvalue internal to the move functions, even though it is declared as an rvalue reference parameter. That's why it is necessary to say move(x) instead of just x when passing down to the base class. This is a key safety feature of move semantics designed to prevent accidently moving twice from some named variable. All moves occur only from rvalues, or with an explicit cast to rvalue such as using std::move. If you have a name for the variable, it is an lvalue.
Named R-value references are treated as L-value.
So we need std::move
to convert it to R-Value.
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