Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does NRVO also apply to coroutines?

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?
}
like image 845
xmllmx Avatar asked Dec 18 '22 13:12

xmllmx


2 Answers

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.

like image 57
eerorika Avatar answered Dec 31 '22 16:12

eerorika


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.

like image 29
Nicol Bolas Avatar answered Dec 31 '22 17:12

Nicol Bolas