When exactly does a reference dangle, and how does lifetime extension change that?
Two of these three cases leave a dangling reference; one is correct. Identify which bind safely and which dangle, and state the rule that decides.
#include <string>
const std::string& makeGreeting(const std::string& name) {
return "Hello, " + name;
}
void caseB() {
const std::string& s = std::string("temp");
}
struct Holder { const std::string& ref; };
void caseC() {
Holder h{ std::string("oops") };
}
int main() {
const std::string& g = makeGreeting("world");
}
Find and fix the bug.
A reference dangles when the object it binds to is destroyed while the reference still lives — using it is undefined behaviour. Binding a const T& to a temporary extends that temporary to the reference's scope. But extension applies only to the direct binding: returning the reference does not extend it.
- ✗Returning a
const T&to a local or temporary — extension does not survive the return - ✗Storing a lifetime-extending reference in a struct member and expecting the temporary to persist
- ✗Binding
const auto& x = vec.front();then mutatingvecso reallocation invalidatesx
- →Why does binding through a function parameter not extend the temporary's lifetime?
- →How do dangling references differ from dangling pointers in detectability?
What is wrong with this code?
#include <string>
// Case A: returning a reference to a temporary
const std::string& makeGreeting(const std::string& name) {
return "Hello, " + name; // temporary std::string destroyed at return
}
// Case B: lifetime extension — works
void caseB() {
const std::string& s = std::string("temp"); // lifetime extended
// s valid until end of caseB()
}
// Case C: extension is NOT transitive
struct Holder {
const std::string& ref;
};
void caseC() {
Holder h{ std::string("oops") }; // temporary dies at end of expression
// h.ref is now a dangling reference
}
int main() {
const std::string& g = makeGreeting("world"); // g already dangles
}
Case A is a bug. The concatenation builds a temporary std::string; lifetime extension does not apply to a value returned from a function. The temporary is destroyed when makeGreeting returns, so g in main dangles immediately.
Case B is correct. Binding a const std::string& directly to a temporary extends its lifetime to the scope of s.
Case C is a bug. Extension applies to the direct binding, not through member initialization. The temporary bound to h.ref dies at the end of the full expression, leaving h.ref dangling.
The rule: only a direct binding of const T&/T&& to a temporary extends its lifetime, and only to the scope of the reference itself. Returns, function parameters, and class members do not extend.