C++ references, const, and auto

Pass large objects without copying, protect them with const, and let the compiler deduce types.

C++
#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";
}
Output
87 96 81
264
81 96
87 0
100

Explanation

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.

Explore the dry run
Guided walkthroughReady
1#include <algorithm>
2#include <iostream>
3#include <vector>
4
5void add_bonus(std::vector<int>& scores, int bonus) {
6 for (int& s : scores) {
7 s += bonus;
8 }
9}
10
11int sum(const std::vector<int>& scores) {
12 int total = 0;
13 for (int s : scores) {
14 total += s;
15 }
16 return total;
17}
18
19int main() {
20 std::vector<int> scores = {82, 91, 76};
21 add_bonus(scores, 5);
22 std::cout << scores[0] << " " << scores[1] << " " << scores[2] << "\n";
23 std::cout << sum(scores) << "\n";
24
25 auto [low, high] = std::minmax_element(scores.begin(), scores.end());
26 std::cout << *low << " " << *high << "\n";
27
28 auto copy = scores;
29 copy[0] = 0;
30 std::cout << scores[0] << " " << copy[0] << "\n";
31
32 auto& alias = scores;
33 alias[0] = 100;
34 std::cout << scores[0] << "\n";
35}

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
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput 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

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.

Further reading