The idea of move semantics is that you can grab everything from another temporary object (referenced by an rvalue reference) and store that "everything" in your object. That helps to avoid deep copying where single construction of things is enough -- so you construct things in a rvalue object and then just move it to your long living object.
Why is it that C++ doesn't allow binding lvalue objects to rvalue references? Both allow me to change the referenced object, so there is no difference to me in terms of accessing internals of referenced object.
The only reason I can guess is function overloading ambiguity issues.
But why C++ doesn't allow binding lvalue objects to rvalue references?
Assuming you mean "Why doesn't C++ allow binding rvalue references to lvalue objects": it does. It just isn't automatic, so you have to use std::move
to make it explicit.
Why? Because otherwise an innocuous function call can surprisingly destroy something you didn't expect it to:
Class object(much,state,many,members,wow);
looks_safe_to_me(object);
// oh no, it destructively copied my object!
vs.
Class object(much,state,many,members,wow);
obviously_destructive(std::move(object));
// same result, but now the destruction is explicit and expected
A note on destructive copying: why I say destructively and destruction above, I don't mean the object destructor ends its lifetime: just that its internal state has been moved to a new instance. It's still a valid object, but no longer holds the same expensive state it used to.
A note on terminology: let's see if we can clear up the imprecise use of lvalue, rvalue etc. above.
Quoting from cppreference for posterity:
an lvalue is
an expression that has identity and cannot be moved from.
So, there's no such thing as an lvalue object, but there is an object which is locally named (or referred to) by an lvalue expression
an rvalue is
an expression that is either a prvalue or an xvalue. It can be moved from. It may or may not have identity.
a prvalue (pure rvalue) is roughly an expression referring to an un-named temporary object: we can't convert our lvalue expression to one of these IIUC.
an xvalue (expiring value) is
an expression that has identity and can be moved from.
which explicitly includes the result of std::move
So what actually happens:
std::move
yields an xvalue expression (which can be moved from) referring to the same object as the lvalue expressionstd::move
.