Why is RVO disallowed when returning a parameter?

Imagine no_rvo is defined in a different file than main so that when compiling main the compiler will only see the declaration

X no_rvo(X x);

and will have no idea whether the object of type X returned has any relation to the argument. From what it knows at that point, the implementation of no_rvo could as well be

X no_rvo(X x) { X other; return other; }

So when it e.g. compiles the line

X const& x = no_rvo(X());

it will do the following, when maximally optimizing.

  • Generate the temporary X to be passed to no_rvo as argument
  • call no_rvo, and bind its return value to x
  • destruct the temporary object it passed to no_rvo.

Now if the return value from no_rvo would be the same object as the object passed to it, then destruction of the temporary object would mean destruction of the returned object. But that would be wrong because the returned object is bound to a reference, therefore extending its lifetime beyond that statement. However simply not destructing the argument is also no solution because that would be wrong if the definition of no_rvo is the alternative implementation I’ve shown above. So if the function is allowed to reuse an argument as return value, there can arise situations where the compiler could not determine the correct behaviour.

Note that with common implementations, the compiler would not be able to optimize that away anyways, therefore it is not such a big loss that it is not formally allowed. Also note that the compiler is allowed to optimize the copy away anyway if it can prove that this doesn’t lead to a change in observable behaviour (the so-called as-if rule).

Leave a Comment