C++ references, const, and auto
Pass large objects without copying, protect them with const, and let the compiler deduce types.
On this page
C++ functions and vectors.
- Pass large objects without copying, protect them with const, and let the compiler deduce types.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
A reference is another name for an existing object. A function that takes std::vector<int>& works on the caller's vector and can change it. A parameter of type const std::vector<int>& also avoids the copy but promises not to modify it, so the compiler rejects accidental changes. Passing big objects by const reference is the usual default.
auto lets the compiler deduce a variable's type from its initializer. Plain auto makes a copy, while auto& makes a reference to the original. A range-based for loop with int& changes the elements in place. Structured bindings, such as auto [low, high], unpack a pair or a tuple into named variables.
Code example
#include <algorithm>
#include <iostream>
#include <vector>
void add_bonus(std::vector<int>& scores, int bonus) {
for (int& s : scores) {
s += bonus;
}
}
int sum(const std::vector<int>& scores) {
int total = 0;
for (int s : scores) {
total += s;
}
return total;
}
int main() {
std::vector<int> scores = {82, 91, 76};
add_bonus(scores, 5);
std::cout << scores[0] << " " << scores[1] << " " << scores[2] << "\n";
std::cout << sum(scores) << "\n";
auto [low, high] = std::minmax_element(scores.begin(), scores.end());
std::cout << *low << " " << *high << "\n";
auto copy = scores;
copy[0] = 0;
std::cout << scores[0] << " " << copy[0] << "\n";
auto& alias = scores;
alias[0] = 100;
std::cout << scores[0] << "\n";
}87 96 81 264 81 96 87 0 100
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
#include <algorithm>#include <iostream>#include <vector> void add_bonus(std::vector<int>& scores, int bonus) { for (int& s : scores) { s += bonus; }} int sum(const std::vector<int>& scores) { int total = 0; for (int s : scores) { total += s; } return total;} int main() { std::vector<int> scores = {82, 91, 76}; add_bonus(scores, 5); std::cout << scores[0] << " " << scores[1] << " " << scores[2] << "\n"; std::cout << sum(scores) << "\n"; auto [low, high] = std::minmax_element(scores.begin(), scores.end()); std::cout << *low << " " << *high << "\n"; auto copy = scores; copy[0] = 0; std::cout << scores[0] << " " << copy[0] << "\n"; auto& alias = scores; alias[0] = 100; std::cout << scores[0] << "\n";}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| A non-const reference: the function changes the caller's vector. | — | — | |
| int& makes each s a reference to an element, so s += bonus changes the vector. | — | — | |
| A const reference avoids copying and forbids modification. | — | — | |
| Each score went up by 5. | — | 87 96 81 | |
| 87 + 96 + 81. | — | 87 96 81 264 | |
| minmax_element returns two iterators, unpacked here by a structured binding. | — | 87 96 81 264 | |
| Dereference the iterators to read the smallest and largest values. | — | 87 96 81 264 81 96 | |
| Plain auto makes a copy, so changing it does not affect scores. | — | 87 96 81 264 81 96 | |
| The original keeps 87. | — | 87 96 81 264 81 96 87 0 | |
| auto& is a reference to the same vector, so the change shows in scores. | — | 87 96 81 264 81 96 87 0 | |
| scores[0] is now 100. | — | 87 96 81 264 81 96 87 0 100 |
Behind the scenes
How C++ processes this code
The C++ compiler produces a native executable. Execution enters main, where objects and function calls perform the work.
Cost and common mistakes
add_bonus and sum are O(n); minmax_element is O(n).
- Forgetting & in a parameter or auto copies the whole object. Copying a big vector on every call is a common performance bug.
- A reference must be bound when it is created and cannot be re-seated. Returning a reference to a local variable is undefined behaviour.
- auto drops references and const unless you write auto& or const auto&.
Try it yourself
What happens if sum takes the vector by value instead?
Reveal answer and reasoning
It still works, but each call copies the whole vector first, which costs O(n) time and memory.