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