0

(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();
jbx
  • 21,365
  • 18
  • 90
  • 144
  • Standards aside, how could that second example possibly work without calling the assignment `operator`? (I'm assuming the state of `myobj` between creation and assignment is observable by your program.) The compiler could first run the destructor and then construct a `new` object in-place. But how is that going to be more efficient than using the assignment `operator`? (And it wouldn't be exception safe either as explained by Steve Jessop.) – 5gon12eder Oct 25 '15 at 22:23
  • @5gon12eder I was pretty sure it wouldn't do it for the reasons you mentioned. But I wasn't sure whether underneath the hood there is some other magic mechanism which detects that a function cannot stop mid-way (it doesn't throw) and passes the call site variable by reference implicitly so that the function updates it directly. – jbx Oct 25 '15 at 22:38

1 Answers1

3

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!

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699