77 Advanced The Hundred
The Maximum That Vanished
saving the winner is what loses it
#include <algorithm>
#include <iostream>
int main() {
int score = 10;
int bonus = 32;
const int& best = std::max(score, score + bonus); // no need to copy an int
std::cout << "inline: " << std::max(score, score + bonus) << "\n";
std::cout << "saved: " << best << "\n";
}
Build it with -O2 and run it. Do the two lines agree?
Answer
Typical output (GCC 11 on x86-64, -O2): inline: 42, then saved: 0. The best score
evaporated between one line and the next.
Why¶
std::max does not hand back an int — it returns const T&, a reference to whichever
argument won, and here the winner is the temporary score + bonus. That temporary dies
at the semicolon, so best refers to a dead int and reading it is undefined
behavior; the inline line is safe only because its temporary is still alive inside the
same statement. Binding a reference to a temporary normally extends the temporary's
lifetime, but only when the binding is direct — a reference handed back by a function
earns no extension, which is why std::min, std::minmax and std::clamp share the
hazard.
It may even appear to work: GCC 11 and 13 recycle the dead slot from -O1 up but print
42 twice at -O0, while Clang 18 prints 42 twice at every -O level. GCC 13's
-Wall flags the binding itself (possibly dangling reference to a temporary
[-Wdangling-reference]), Clang 18 stays silent, and -fsanitize=address reports
stack-use-after-scope on both.
The fix¶
Take the winner by value — it is an int, the copy costs nothing:
Takeaway: an algorithm that returns a reference returns it into one of your arguments, temporaries included — store the result by value.
Try it: g++ -std=c++17 -O2 main.cpp -o demo && ./demo