There are many questions on this site about return value optimization (I suppose it’s a fairly confusing topic), but I can’t seem to find one that answers my particular question. If I have code that looks like this:
returnType function() { stuff....}
void someOtherFunction()
{
returnType var = function();
more stuff...
}
I am told that the compiler may decide to not use two instances of returnType in someOtherFunction(). Logically, I would expect that function() would generate an object of type returnType, and someOtherFunction() would receive that value via copy constructor (overloaded or not) into a temporary value. I would then expect that temporary value to be copied via assignment (which could be overloaded and in theory could have any kind of functionality!) into var, which would have previously been initialized via the default constructor.
I see a potential issue here. What happens if there is not this temporary copy of returnType in someOtherFunction()? Wouldn’t var have to be filled, via copy constructor, with the returned value from function() directly? If so, wouldn’t the assignment operator never be called? If so, and if the assignment operator were overloaded, couldn’t that change the functionality of the program? If so, does that mean that it’s the programmer’s responsibility to ensure that = always does the same thing as a copy constructor? And I hate to run this long chain of questions, but if so, why does C++ allow you to define copy constructors to do something other than assignment?
Well, for starters, that’s quite wrong.
Those two lines are the same thing- a constructor call. There are some differences- the first cannot call explicit constructors, I believe- but they are the same function call. There is no default construction and no assignment operator call. They are both direct constructions.
Basically, the Standard says “If you do something other than copying an object in the copy constructor, it’s your own dumb fault and I laugh as your program doesn’t exhibit the expected behaviour when the optimizer eliminates the calls”. Those are my own paraphrased words, of course, but the Standard is very explicit on the optimizer being allowed to eliminate copies. In C++0x then this applies to moves too.
Your code fragment above is really
That isn’t the optimized version, that’s what it really is. The assignment operator is never called. And with NRVO, it looks something like
Of course, the compiler also has to deal with destructing the object even in the case of an exception, and making sure all aliases are of the correct type, and alignment, and some other things I didn’t deal with in my sample, but hopefully you get the general gist.