Skip to content
Theory · References and Pointers · lesson 1 of 8

References, lvalues and rvalues

A reference is not only a function parameter. It can also be declared as an ordinary variable, and then it becomes a second name for another variable:

C++
#include <iostream>

int main() {
    int score = 10;
    int& ref = score;
    ref = ref + 5;
    std::cout << score << '\n';  // 15
}

ref is neither a new variable nor a copy. ref and score denote the same place in memory, so a change made through one name shows through the other. A reference initialized with another reference binds to the same variable: after int& alias = ref;, the name alias also denotes score.

One variable for life

The variable a reference refers to is chosen once, in its declaration. That is why a reference without an initializer does not compile: int& ref; is an error. A reference cannot be re-bound to another variable later either. Assigning through a reference changes the value of the variable it is bound to:

C++
#include <iostream>

int main() {
    int first = 10;
    int second = 20;
    int& ref = first;
    ref = second;
    std::cout << first << ' ' << second << '\n';  // 20 20
}

The line ref = second; writes the value of second, that is 20, into first. After it, ref still denotes first: if second changes later, neither first nor ref changes.

What a reference binds to

An expression that denotes a variable is called an lvalue: for example, score or ref. The literal 5 or the result of score + 1 is an rvalue: a nameless value stored in no variable. An int& reference binds only to an lvalue.

A const reference, const int&, accepts an rvalue too. The compiler then creates a temporary object, a nameless variable holding the value, and binds the reference to it. Such an object lives as long as the reference:

C++
#include <iostream>

int main() {
    int score = 10;
    const int& next = score + 1;
    score = 50;
    std::cout << next << '\n';  // 11
}

next denotes a temporary object with the value 11, not score, so changing score does not affect it. For the same reason, a const int& parameter accepts literals and expressions.

Common mistake

A plain reference is bound to the result of an expression:

C++
int main() {
    int a = 2;
    int b = 3;
    int& sum = a + b;  // ✗
    return sum;
}
TEXT
error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'

a + b is an rvalue: the sum is not stored in any variable, so an int& cannot bind to it. If sum does not need to change, declare it as const int&. More often, though, an ordinary variable is what you need: int sum = a + b;.