C++中返回绑定到临时对象的引用参数的引用导致悬垂引用的规则解析及编译器行为疑问
Hey, that's a really interesting observation—let's unpack what's going on here, because what you're seeing is a perfect example of how undefined behavior (UB) can sometimes look like it's working as expected.
First: Why the standard says sum is a dangling reference
Let's recap the core rule: When a temporary is bound to a reference parameter of a function, its lifetime only lasts until the end of the full expression containing that function call. In your code:
X&& sum = a + b + c + d;
- The first
a + bcreates a temporaryXobject. - Each subsequent
operator+(X&&, const X&)takes that temporary's rvalue reference, modifies it, and returns a reference to it. - The full expression here is the entire chain
a + b + c + d. Once this expression finishes, the temporary object thatsumis bound to reaches the end of its lifetime—it doesn't get extended just becausesumis referencing it, because this temporary was returned via a function reference, not directly bound tosumduring initialization.
By the letter of the C++ standard, sum is absolutely a dangling reference, and accessing it is undefined behavior.
So why aren't compilers breaking your code?
This comes down to compiler implementation details, not any guarantee from the standard:
- Most compilers (GCC, Clang, MSVC) allocate temporary objects like this in the current function's stack frame (in your case,
main's stack frame). When you callanotherFunc, its stack frame is allocated on top ofmain's frame (since stacks grow downward on most systems). The big array inanotherFuncuses space in its own stack frame, which doesn't overlap with the temporary inmain's frame. - Undefined behavior doesn't mean "your program must crash immediately"—it means the standard gives no guarantees about what happens. The compiler isn't required to actively overwrite or invalidate the memory of the expired temporary; if nothing else uses that memory location, the old data will just sit there.
If you tried a scenario where the compiler chose to allocate the temporary in a region that gets overwritten (e.g., a deeper call stack with larger allocations), you'd likely see crashes or garbage values.
Why Howard Hinnant warned about this for std::string
The reason std::string avoids this design is that relying on compiler-specific stack behavior is risky. Even if your test case works, there's no guarantee it will work across all compilers, optimization levels, or more complex program structures. The standard library prioritizes portability and correctness according to the standard, not relying on non-standard implementation quirks.
内容的提问来源于stack exchange,提问作者Ruperrrt

