In the following example, NRVO (Named Return Value Optimization) applies as per this article:
std::string f1()
{
std::string str;
return str; // NVRO applies here!
}
However, consider:
task<std::string> f2()
{
std::string str;
co_return str; // Does NVRO also apply here?
}
I know that NRVO (Named Return Value Optimization) is mandatory since C++17:
It is not. NRVO is still an optimisation.
The non-named Return Value Optimisation (RVO) is mandatory.
// Is NVRO also guaranteed here?
No, because NRVO is never guaranteed.
For completeness, guaranteed elision in C++17 only applies to returning a prvalue from a function directly. Returning a named variable is only subject to elision if the compiler feels like it.
As for the meat of your question, co_return
values are never subject to copy elision, guaranteed or otherwise. Elision for return values keys off of the return
keyword, and coroutines aren't allowed to use return
. They use co_return
, which the elision logic in the standard doesn't key off of. So elision does not apply.
The reason why this was done is because of how coroutines work. A coroutine is a function that has a promise object in it. This promise object is how you shepard the coroutine's co_return
value (and other state) to the "future" object that the coroutine function returned.
Elision works in normal functions because calling conventions require the caller to pass the storage for a return value to the function. So the function's implementation can choose to just build the object in that storage rather than building a separate stack object and copying into it upon return
.
In a coroutine, the return value lives inside the promise, so that can't really happen.
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