Return value optimization

From Cppwiki

Jump to: navigation, search

Return value optimization is the name given to special, yet highly common, form of copy elision. Most compilers support at least some form of RVO.


Invoking RVO

The problem that RVO addresses is when something gets returned from a function "by value" a copy must normally be made. The standard, however, allows for some of these copies to be omitted as long as the behavior of the program remains "as if" the original copy had been made. This allows compilers to possibly avoid the otherwise costly operations of copying an object.

If we look at the following code,

struct foo 
foo(int one = 0, int two = 0) : x(one), y(two) {}
int x, y; 
foo bar(int one, int two)
return foo(one, two);
int main()
 foo f = bar(5, 7);

We can see that the standard says that the following could take place in order to create f:

  1. First call bar
    1. bar creates an unnamed object of type foo, and initalizes it by direct initialization
    2. bar returns this unnamed object "by value"
  2. foo f is created, using its copy constructor to copy the return value of bar

This is a rather wasteful, and expensive process, and so compilers instead are allowed to take the liberty of taking the return value from a function, and directly substituting f in place of where the unnamed object would be created by the return. In other words, steps 1.1, and 1.2 above are eliminated, and step 2 becomes "Directly initialize f from the return specified by the callee." This prevents any copy from being made.

The full rules of copy elision allow the above sequence to be further optimized.


Most compilers have some limitations on when they can invoke the RVO mechanism. Generally speaking, plain RVO will only work if the function

  • Only has one point of return
  • Initializes its return in the return statement (as the above code does).

Named RVO

Named RVO, or NRVO, is a further extension of RVO that avoids one of the two major limitations to the RVO mechanism; that of having to initialize an object at the single point of return.

Take the following:

SomeStruct foo(...)
SomeStruct ret;
/* ... */
return ret;

In some cases, compilers can take this single return object and apply RVO to it as well. This is called Named RVO because the return object is named in initializing function.

NRVO often has its own set of limitations, and they vary widely by compiler. Some of these limitations include:

  • A single point of return
  • The object may not be conditionally initialized
  • The function may not be able to use exceptions

With NRVO, the behaviour of the program can in fact change due to the copy-constructor call being removed. For example, the copy-constructor might have has a lasting side-effect without NRVO, but does not get executed with NRVO.

See Also

Personal tools