Is Rvo (Return Value Optimization) Applicable for All Objects

Is RVO (Return Value Optimization) applicable for all objects?

Return Value Optimization can always be applied, what cannot be universally applied is Named Return Value Optimization. Basically, for the optimization to take place, the compiler must know what object is going to be returned at the place where the object is constructed.

In the case of RVO (where a temporary is returned) that condition is trivially met: the object is constructed in the return statement, and well, it is returned.

In the case of NRVO, you would have to analyze the code to understand whether the compiler can know or not that information. If the analysis of the function is simple, chances are that the compiler will optimize it (single return statement that does not contain a conditional, for example; multiple return statements of the same object; multiple return statements like T f() { if (condition) { T r; return r; } else { T r2; return r2; } } where the compiler knows that r or r2 will be returned...)

Note that you can only assume the optimization in simple cases, specifically, the example in wikipedia could actually be optimized by a smart enough compiler:

std::string f( bool x ) {
std::string a("a"), b("b");
if ( x ) return a;
else return b;
}

Can be rewritten by the compiler into:

std::string f( bool x ) {
if ( x ) {
std::string a("a"), b("b");
return a;
} else {
std::string a("a"), b("b");
return b;
}
}

And the compiler can know at this time that in the first branch a is to be constructed in place of the returned object, and in the second branch the same applies to b. But I would not count on that. If the code is complex, assume that the compiler will not be able to produce the optimization.

EDIT: There is one case that I have not mentioned explicitly, the compiler is not allowed (in most cases even if it was allowed, it could not possibly do it) to optimize away the copy from an argument to the function to the return statement:

T f( T value ) { return value; } // Cannot be optimized away --but can be converted into
// a move operation if available.

Is RVO (Return Value Optimization) on unnamed objects a universally guaranteed behavior?

According to the standard, the program can print 0, 1 or 2. The specific paragraph in C++11 is 12.8p31 that starts with:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects.

Note that both copy elisions are not an optimization that falls in the as-if rule (which requires the behavior of the program to be consistent with the behavior of the same program as-if no optimization had taken place). The standard explicitly allows the implementation to generate different observable behaviors, and it is up to you the programmer to have your program not depend on that (or accept all three possible outcomes).

Note 2: 1 is not mentioned in any of the answers, but it is a possible outcome. There are two potential copies taking place, from the local variable in the function to the returned object to the object in main, the compiler can elide none, one or the two copies generating all three possible outputs.

Can I rely on named return value optimisation for complicated return types?

Before C++17, you cannot rely on copy elision at all, since it is optional. However, all mainstream compilers will very likely apply it (e.g., GCC applies it even with -O0 optimization flag, you need to explicitly disable copy elision by -fno-elide-constructors if you want to).

However, std::set supports move semantics, so even without NRVO, your code would be fine.

Note that in C++17, NRVO is optional as well. RVO is mandatory.


To be technically correct, IMO, there is no RVO in C++17, since when prvalue is returned, no temporary is materialized to be moved/copied from. The rules are kind of different, but the effect is more or less the same. Or, even stronger, since there is no need for copy/move constructor to return prvalue by value in C++17:

#include <atomic>

std::atomic<int> f() {
return std::atomic<int>{0};
}

int main() {
std::atomic<int> i = f();
}

In C++14, this code does not compile.

Isn't return value optimization (RVO) a bug?

The standard mandates that operations with concern a program's observable state must not be optimized away, except for copy construction in certain circumstances. You must not rely on copy constructors to be executed, even if they have side effects you expect to see (e.g., console output).

Why return value optimization does not work when return ()

This is NRVO, not RVO.

Here is the rule which allows NRVO (class.copy/31):

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv- unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

As you can see, in the case of (a), the expression is not a name (because of the added parenthesis), so NRVO is not allowed.



Related Topics



Leave a reply



Submit