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 = 0 — v 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