Const lvalue reference is useless
16 Dec 2020 - John Z. Li
If an object is const
qualified,
it means that it should not and perhaps could
not be modified during its lifetime.
After rvalue reference is introduced for
implementing move semantics,
the thing gets a bit complicated.
By the language standard, after an object is moved,
the moved-from object is in a valid but unspecified state,
that is, the object might be modified after being moved.
This contradicts constness of a const
qualified object.
While designating parameter types of a function,
if the programmer intends to copy an object,
he could simply pass by value or pass by const lvalue reference.
If he intends to move the object, he will pass by rvalue reference.
This is reflected in C++ down to the standard library level,
for example, the push_back()
member function of the std::vector
class has two overloading:
void push_back( const T& value ); //for copying
void push_back( T&& value ); //for moving
What if one passes a const rvalue to push_back
?
Because a const rvalue can not bind to non-const rvalue reference type,
the first overloading is selected, that is, the object is copied, instead of being moved.
This, is quite counter-intuitive, though in this case, the const-ness of the object is respected.
const T obj;
std::vector<T> v;
v.push_back(std::move(obj)); //this code actually copied the object.
Even if an overloading that takes const rvalue reference
is added to the interface of std::vector
,
the right thing to do is still simply copying the object,
because moving a const object is paradoxical.
It is thus obvious that const rvalue reference is useless?
The only time it is been used in the standard library, as far as I know,
is in the std::reference_wrapper
class to disable rvalues from
binding to ref()
and cref()
.
A type exists sorely for the purpose that functions
taking it as parameter type can be explicitly deleted.
If we think about it, it clearly indicates a design flaw of the language.
If const rvalue reference is disallowed in the language in the first place,
one could simply disable ref()
and cref()
on rvalues as below:
// note this not how ref and cref are implemented in the standard library.
template <class T> void ref (T&&) = delete;
template <class T> void cref (T&&) = delete;
No one will miss it for any reason.