twice()0x0c14main()0x1c51void twice(int& n) {void twice(const int& n) {2 n = n * 2;error3}4int main() {5 int score = 5;6 int& ref = score;7 ref = 7;8 twice(score);9 return score;10}nscoreref5714
Violet card and tags: the code and the names it uses (score, ref, n)Sand slabs: stack frames; blue block: an int box in memoryKhaki tokens: values moving into and out of the boxLeft: the code card refs.cpp. Right: two stack frames, main's in front with one int box for score, and the room where twice's frame appears while twice runs. The violet name tags score, ref and n all sit on the same box: a reference is a second name, not a new box. Writing through any of them changes the one value, 5 to 7 to 14. Without the &, the call copies 14 into a new box in twice's frame, and only the copy is doubled. With const&, n names score's box again, but line 2 is struck: writing through a const reference does not compile. The program on the card is real, standard C++. It compiles with no warnings under g++ or clang++ -std=c++20 -Wall -Wextra, and ./refs exits with status 14.

One box, two names

  1. int score = 5; makes a variable: a box of memory in main's stack frame, holding 5. The name score is how your code reaches that box.

Reference parameters

Copy or reference?

What happens

;; step 1/9 · variable
line 5   int score = 5;
box      0x1c  (an int, 4 bytes on common systems)
value    5
names    score
the box lives in main's stack frame

Addresses such as 0x1c are short made-up examples. Real stack addresses are much longer and change from run to run. The C++ standard does not say how a reference is stored: a reference is not an object and need not take any memory. In practice a reference parameter such as int& n is usually passed as the address of the argument, much like a pointer.