Search code examples
c++rvonrvo

Does (N)RVO also happen when the value is being copied into an existent object?


(N)RVO helps to avoid unnecessary copying and creating of temporary objects when the return value is being assigned into a new variable (thus avoiding the copy constructor).

So something like this should be optimized by RVO:

MyObj getMyObj() {
  return MyObj();
}

MyObj myobj = getMyObj();

However, will it also happen when the call site object already exists? (I.e. in the case where the = operator is used instead of the copy constructor). I tried to find literature about this but (N)RVO seems to be always described in terms of avoiding the copy constructor. Not sure if it is actually safe to modify the call site object in this case.

MyObj myobj;

//will getMyObj() first create a temporary object and then copy it via the = operator?
myobj = getMyObj();

Solution

  • No, RVO doesn't apply. (N)RVO is defined in the standard solely as constructor elision.

    The motivation is that if the constructor of MyObj() throws, then in the second code snippet myobj already exists, and should continue to exist in the state that it was in before the call to getMyObj().

    Besides which, I don't think it's clear in general how the construction in-place would actually be achieved. myobj is an already-constructed object, and only operator= "knows" how to replace any resources it holds, with different resources.

    The return value of getMyObj can still be constructed directly, though, and the calling code can benefit from an operator=(MyObj &&) (move assignment) if there is one. So the code doesn't necessarily require either a copy construction or a copy-assignment, but it does demand an assignment, which can't be elided.

    If everything is inlined, and MyObj() can't throw, and the assignment has no side-effects, then on a good day the compiler might apply the "as-if" rule, and optimise regardless of the specific rules of (N)RVO!