Say I have the following function
void doWork(Widget && param) // param is an LVALUE of RRef type
{
Widget store = std::move(param);
}
Why do I need to cast param
back to an rvalue with std::move()
? Shouldn't it be obvious that the type of param
is rvalue since it was declared in the function signature as an rvalue reference? Shouldn't the move constructor be automatically invoked here on this principle alone?
Why doesn't this happen by default?
Yes, rvalues are moved, lvalues are copied. But when there's no according move operation, rvalues are copied as well.
rvalue references have two properties that are useful: rvalue references extend the lifespan of the temporary object to which they are assigned. Non-const rvalue references allow you to modify the rvalue.
An lvalue reference can bind to an lvalue, but not to an rvalue.
So an rvalue can be used both with rvalue overloads and a const lvalue reference.
with your design:
void doWork(Widget && param)
{
Widget store1 = param; // automatically move param
Widget store2 = param; // boom
Widget store_last = param; // boom
}
with current design:
void doWork(Widget && param)
{
Widget store1 = param; // ok, copy
Widget store2 = param; // ok, copy
Widget store_last = std::move(param); // ok, param is moved at its last use
}
So the moral here is that even if you have an rvalue reference you have a name for it which means you can use it multiple times. As such you can't automatically move it because you could need it for a later use.
Now let's say you want to re-design the language so that the last use is automatically treated as an rvalue.
This can be easily done in the above example:
void doWork(Widget && param)
{
Widget store1 = param; // `param` treated as lvalue here, copy
Widget store2 = param; // `param` treated as lvalue here, copy
Widget store_last = param; // `param` treated as rvalue here, move
}
Let's ignore the inconsistency of how param
is treated (which in itself is a problem).
Now think what use of param
is the last use:
void doWork(Widget && param)
{
Widget store2 = param; // this can be last use or not
while (some_condition())
{
Widget store1 = param; // this can be both last use and not
}
}
The language simply cannot be designed this way.
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