References and const-correctness
Give a variable a second name, and let const guard your intentions
const and you gain a compiler-enforced promise: "I will read this, but I will not modify it." Together, references and const let you pass large objects cheaply, write self-documenting interfaces, and catch a whole class of bugs at compile time instead of at 3 a.m. in production.
- explain what an lvalue reference is and how it differs from a pointer,
- pass parameters by
constreference to avoid copies without risking mutation, - write
constmember functions and understand what they guarantee, - reason about why const-correctness makes larger programs safer and clearer.
1. What exactly is a reference?
An lvalue reference is a name that refers to an object that already exists. When you write int& r = x;, you are not making a copy of x and you are not creating a new object — you are giving the same object a second name. From that point on, r and x are two labels on one box in memory.
Two rules define a reference and separate it from every other C++ tool:
- It must be initialized. There is no such thing as an uninitialized reference.
int& r;does not compile — a reference must bind to something the moment it is born. - It can never be re-seated. Once
rrefers tox, it refers toxfor its entire life. Writingr = y;does not makerpoint aty; it copies the value ofyintox.
#include <iostream>
int main() {
int x = 10;
int& r = x; // r is another name for x
r = 20; // writes through r -> changes x
std::cout << x << '\n'; // prints 20
int y = 99;
r = y; // NOT re-seating: copies y's value into x
std::cout << x << '\n'; // prints 99
std::cout << &r << " == " << &x << '\n'; // same address
}
Because r and x share one address, taking &r and &x yields the identical pointer. A reference has no separate storage of its own that you can observe — it truly is the object under another name.