1. Problem It Solves
A range expression can contain nested temporaries. C++23 extends the lifetime of temporaries created inside the for-range-initializer through the loop, preventing important dangling-reference patterns. The goal is to make the relevant rule visible in code instead of relying on an assumption about what “C++23 support” means.
2. Prerequisites
Day 3: temporary-object lifetime.
Day 5: ranges, iterators, and sentinels.
3. Core Idea
The loop secretly keeps the evaluated range expression alive in a hidden variable. C++23 also protects supporting temporaries in that initializer, subject to normal parameter-lifetime exceptions. Read the syntax from left to right, identify the value, object, or range being transformed, and then check its resulting type, lifetime, or ownership. Standardization and implementation are separate: a C++23 mode may still lack one library component, so a feature-test macro is part of responsible portable use.
4. Minimal Syntax
for (char c : make_words().front()) { use(c); }5. How It Works
The sample builds the smallest expression or object needed for Range-Based
forLifetime Extension.It iterates characters obtained through an element of a temporary container when supported. The compiler and library apply the relevant rule before the program observes the result.
The program prints or checks the full word without reading destroyed storage, making the important behavior easy to verify.
6. Common Mistakes
Assuming every function parameter temporary is extended is wrong; a function returning a reference to a by-value parameter still returns a dangling reference.
Enabling C++23 mode without checking the relevant feature macro may select code that the installed compiler or standard library does not implement yet.
7. When to Use It
Use it when the task involves compact loops over subobjects or views created within a safe for-range-initializer.
Avoid it when the task involves clever chains whose ownership and reference relationships are hard to prove.
8. Simple Example
A loop displays characters from the first string in a temporary list returned by a helper. The downloadable program keeps the data fixed so the output can be compared without entering input.
Complete sample code
Source file
cpp23/17_range_for_lifetime_extension/main.cpp
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> make_words() {
return {"C++23"};
}
int main() {
#if defined(__cpp_range_based_for) && __cpp_range_based_for >= 202211L
// C++23 keeps supporting temporaries alive through the loop.
for (char letter : make_words().front())
std::cout << letter;
#else
auto words = make_words();
for (char letter : words.front())
std::cout << letter;
#endif
std::cout << '\n';
}
9. Key Takeaways
Separate the language rule from compiler and library availability.
Keep lifetime, ownership, and deduced types visible when they affect correctness.
Prefer the smallest syntax that communicates the intent.
Guard facilities that are not yet uniformly implemented.
10. Self-Check Questions
Easy — What is the smallest syntax in Section 4, and what main job does it perform?
Medium — Read the sample program: which value, type, or branch is observed, and why?
Hard — Which temporaries are extended in
for (auto x : f().g()), and why can a dangling reference returned from insideg()remain unsafe?