Skip to content

30 Intermediate The Hundred

auto Never Deduces a Reference

the update that goes nowhere

#include <iostream>

struct Counter {
    int hits = 0;
    int& value() { return hits; }
};

int main() {
    Counter c;

    auto v = c.value();
    v = 99;
    std::cout << "v = " << v << ", c.hits = " << c.hits << "\n";

    auto& r = c.value();
    r = 99;
    std::cout << "r = " << r << ", c.hits = " << c.hits << "\n";
}

Run it. Does the first assignment change the counter?

Answer

No. It prints v = 99, c.hits = 0v is a plain int, a copy. Only the auto& line reaches the counter: r = 99, c.hits = 99.

Why

auto deduces types by the same rules as a by-value template parameter, and those rules strip references (and top-level const) before choosing the type. value() returns int&, but the reference evaporates in deduction: v is an independent int initialized from hits, so v = 99 writes to the copy and the counter never moves. Nothing here is suspicious enough for the compiler to flag — -Wall -Wextra stays completely silent. The same invisible copy lurks in range-for: for (auto s : words) copy-constructs a whole std::string every iteration.

The fix

Write the & yourself — deduction will never write it for you:

auto& v = c.value();           // a real reference — writes land on the counter
const auto& cv = c.value();    // reference, read-only
for (const auto& s : words)    // no per-element copies

Takeaway: auto copies unless you say otherwise — write auto&, const auto&, or auto&& when you mean a reference.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry