Lesson 122 +10 XP

Value Categories: Lvalues and Rvalues

Value Categories: Lvalues and Rvalues

Every expression in C++ is either an lvalue or an rvalue. The historic terms mean "left value" and "right value", but the real test is the address.

Lvalue: a home in memory

An lvalue is an expression that refers to an object, something that lives at a memory address. A named variable is the classic example:

#include <iostream>
using namespace std;

int x = 5;
x = 10;        // we can assign to it (it has an address)
int* p = &x;   // we can take its address

Because x sits in memory, it has an identity and can be the topic of an assignment.

rvalue: a temporary

An rvalue is a temporary that is used for its value only - it has no persistent address:

5;            // a literal number
x + 1;        // the result of the calculation

There is no &5 - the value appears, is used, and evaporates.

A plain reference needs an lvalue

int& ref1 = x;   // ok: x is an lvalue with an address
int& ref2 = 5;   // error: 5 has no address to bind

An int& must bind to an lvalue. A temporary won't do.

const reference can bind to temporaries

const int& ref = 5;   // ok! temporary lives as long as const&

A const int& is allowed to bind to an rvalue, because the compiler keeps the temporary alive for the lifetime of the reference - which is why functions accept literals with a const T&:

void printValue(const int& v) {
    cout << v << endl;
}
printValue(7);   // fine

TL;DR

  • An lvalue is a value with a memory address (a variable).
  • An rvalue is a temporary value with no persistent address.
  • int& binds only to lvalues.
  • const int& can bind to temporaries too.