rvalues
The One True Definition of rvalues and lvalues in C++:
- If an expression is the name of a function, it is an lvalue.
- Otherwise, if the expression can be provided to
std::addressofand the program compiles, it is an lvalue. - In all other cases, the expression is an rvalue.
Some Elaborations:
This definition uses std::addressof instead of
& because custom types can have the
& operator overridden.
Since rvalues cannot be provided to
std::addressof while most lvalues can, I like to
say that lvalues are “locatable values” and rvalues are
“reticent values.”(Reticent can mean “inclined to silence” or
“secretive,” so we mean that rvalues are reticent
regarding memory addresses.) The only lvalue which cannot be
provided to std::addressof are names of
overloaded functions.
C++ would be a better-designed language if function names were not lvalues. However, this designation was made early in the language’s lifespan and the C++ standards committee is insistent on backwards-compatability, so we are stuck with the absurdity that names of overloaded functions are lvalues. (I can only assume that this decision was made because many lvalues are names of variables, and there was thought to be some sort of consistency or symmetry if function names were also lvalues.)
When you look at what expressions are lvalues and which are
rvalues, there is usually good sense for the designation.
lvalues are expressions whose values are safe to reveal to the
programmer. Variable names can have their addresses exposed
because the values are guaranteed to have lifetime. String
literals can have their addresses exposed because the C++
standard demands that the string literals have static lifetime.
It would be ridiculous to hide the address of result of a
* used to dereference a pointer. And so on. On the
other hand, most rvalues are the result of some sort of
temporary computation like results of mathematical operators
(+, *, etc.) or boolean operators
(&&, ||, etc.). At the time
these expressions are computed it is not yet determined whether
it has been assigned to any persistent storage with
=, so the program protects the programmer from
knowing their memory addresses. There are, of course, bad
designations because C++ is a poorly designed language
(invocations of functions that return lvalue references are
lvalues!!!) but these sorts of things are always to be expected
with C++. And if you are ever unsure about whether an expression
is an rvalue or lvalue, it is an easy thing to learn: simply
provide the expression to std::addressof and see if
the compiler likes it.
For stupid reasons in 2011 that are not worth discussing, C++ decided that all rvalues can be more specifically designated as either a prvalue or xvalue. I have spent more time than any human being ever should to understand what xvalues and prvalues are. Having accomplished this task I have come to the conclusion that this is not useful information to know. All you need to know is that they are rvalues.
For a complete list of all kinds of rvalues and lvalues you should consult cppreference’s article about value categories. Unfortunately, this document adopted the prvalue and xvalue terminology introduced in C++11. Do not read the preamble at the beginning of the document; it is incomprehensible.