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).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…