I am confused about the lifetime of temporaries passed to coroutine tasks. Consider this example:
cppcoro::task<> UseObject(Object const& object);
cppcoro::task<> CallUseObject() {
co_await UseObject(Object()); // is this valid?
}
If these were functions returning void, then the Object()
passed to UseObject
would be destroyed at the semi-colon (i.e. after UseObject
completes). However, I'm not sure if the same applies for coroutines. Is passing a temporary to a routine by reference safe? When do temporaries get destroyed if it isn't at the semi colon?
Furthermore, as a sanity check, is it always safe to write:
cppcoro::task<> CallUseObject() {
Object stayingalive;
co_await UseObject(stayingalive);
}
since staying_alive
is destroyed after co_await finishes?
This is actually subject of an open issue with the current draft. To quote the issue:
The intent is that copies/moves of parameters (if required) are created preserving the exact type (including references, r-references, etc). The wording in 11.4.4[dcl.fct.def.coroutine]/11 does not seem to express that clearly.
Based on that, it would seem that the coroutine frame will capture a reference to the temporary.
Since co_await
is an expression, the temporary should get destroyed at the end of the full expression in which it appears. Whether your code above is safe or not will depend on whether the concrete implementation of the two coroutines involved makes it safe to co_await
on a call to UseObject
with a reference to a temporary. Specifically, note that what co_await
does depends on both, the type of the expression it's applied to as well as the promise type of the coroutine it appears in. Additionally, UseObject
(which we don't know the definition of) could, at least in principle, do all sorts of weird things with the reference it's given…
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