Consider the following code snippet:
struct foo { };
template <typename F>
struct impl : F
{
impl(F&& f) : F{std::move(f)} { }
auto get() { return (*this)(); }
};
template <typename X>
auto returner(X&& x)
{
return impl{[&x]{ return x; }};
// ^~
}
int main()
{
auto x = returner(foo{}).get();
}
live example on wandbox.org
Is it guaranteed that foo{} will be alive for the entire duration of the returner(foo{}).get() expression?
Or is foo{} going to be alive only for returner(foo{}), thus causing undefined behavior when invoking impl::get()?
The Standard says in [class.temporary]:
Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created.
In [intro.execution]
A full-expression is
an unevaluated operand,
a constant-expression,
an init-declarator or a mem-initializer, including the constituent expressions of the initializer,
an invocation of a destructor generated at the end of the lifetime of an object other than a temporary object ([class.temporary]), or
an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.
I am not sure whether or not the full-expression related to foo{} is returner(foo{}) or returner(foo{}).get().
The important section here is that:
A full-expression is [...] an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.
So in returner(foo{}).get(), returner(foo{}) is a subexpression of the expression returner(foo{}).get(), so it's not a full-expression. Hence:
Is it guaranteed that
foo{}will be alive for the entire duration of thereturner(foo{}).get()expression?
Yes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With