lifetime of local variable
Channel
C++ weekly
Topics
Object lifetime Return value This SO thread is a rough sum-up of the issue: https://stackoverflow.com/questions/73481385/how-to-determine-when-local-variables-are-destroyed
What is a function local object lifetime?
How does it depend on it being part of the return expression?
How does it depend on the returned type (plain value, l/rvalue reference)?
How does it depend on the call site (here is a very contrived example : https://godbolt.org/z/dEqoMP3ca where a temporary is returned as rvalue reference, binding it to a plain object leads to dangling reference and UB while binding it to a const& expand the lifetime of the bound objet; NB I designed the foo function to avoid (N)RVO).
I found many related questions on SO but it's always focused on a very special case (as imposed by SO) making it difficult to have the "big picture".
Length
I honestly don't know if the subject can be treated in less than 10 minutes or not
https://stackoverflow.com/questions/79377674/order-of-execution-in-c-program : raises also questions about the status and lifetime of function argument.
somewhat related: returning a reference to a local temporary: https://stackoverflow.com/questions/79450819/r-value-reference-to-default-argument-temporary-to-hold-the-buffer-for-convertin
the use-case seems ok but the tc_str function can be easily misused by getting a reference on the return value, which will eventually get dangling.
I'm doing a much higher level introduction than you asked for, I want people to do their own research and learn on their own here: https://compiler-explorer.com/z/n8bd7hhhh
Hi and thank for your feedback
I played a bit about the notion of returned value : https://godbolt.org/z/YGeP364Wz It helped me construct a mental model of it as I failed to find a clear definition of it in the standard. I imagine it as a (possible) hidden variable that is initialized with the result of the return expression and is then available at the call site. It can be sometime be skipped elided ((N)RVO), plus other details with respect to movability, assignement vs initialization,... What I couldn't understand is, in case of actual construction of the returned value, is it done by the callee or by the caller? This helps to some extent, to understand, when exactly, the lifetime of a local variable ends.
Space for the returned object is allocated by the caller, but only the callee knows how it should be constructed, so the callee does the construction of the return object into the space provided by the caller. If there is a single unambiguous named value being returned on all branches you'll likely get named return value optimization, and in that case when you take the address of the return value before returning it, you'll see its address is already where it's being returned to. As for who is responsible for destruction, I think the callee destroys the returned object if the function exits via exception, and in all other cases the caller destroys the return object with normal rules about objects going out of scope.
experimentally, it seems to comply with what you're saying. If RV construction throws, it's in callee: https://godbolt.org/z/Pnv3zzz79
This might be a better test maybe? Though it's still difficult to tell who exactly runs the destructor here: https://godbolt.org/z/xW9PhdMTP Also I don't know why MSVC doesn't print the destructor text, maybe there's a compiler bug here?
Coming in Ep498