rvalues

published 2026-Nov-05 23:39:59

The One True Definition of rvalues and lvalues in C++:

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.

It is not cppreference’s fault that this section is bad, this is actually one of the most correct and coherent descriptions of C++ value categories on the internet. The problem is with nonsensical and arbitrary classifications made by the C++ standard.