Pass by Value, by Reference, and const&
Copies vs aliases: why small values pass by value, why strings and vectors pass by const&, and a first taste of out-parameters.
Pass by value: a photocopy
void double_it(int x) { // x is a COPY
x = x * 2; // changes the copy, not the caller's variable
}
int n = 5;
double_it(n);
std::cout << n; // still 5
By value, the function works on a photocopy. Safe, simple, and free for small things: int, double, bool, char.
Pass by reference: the real thing
A reference (&) is an alias — another name for the caller's actual variable:
void double_it(int& x) { // x IS the caller's variable
x = x * 2;
}
int n = 5;
double_it(n);
std::cout << n; // 10
This is how a function hands results back through its parameters (an "out-parameter"). It is also how you accidentally modify things — so by default, don't.
The workhorse: const reference
Reading a big object (a std::string, a std::vector) by value copies the whole thing — wasteful. Reading it by non-const reference grants write access you do not want. The answer is const&:
int count_vowels(const std::string& text) { // no copy, no writes
int count = 0;
for (char c : text) {
char lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
if (lower=='a'||lower=='e'||lower=='i'||lower=='o'||lower=='u') ++count;
}
return count;
}
The course rule: small values by value; everything else by const&; plain & only when the function is supposed to modify the caller's object. You will see const std::string& in nearly every function signature from now on — it is the professional default.
(References are deep-dived again in module 11, where they meet pointers. Here, treat & as "the real variable" and const& as "the real variable, read-only".)