Reputation: 4666
Consider the following code:
LargeObject getLargeObject()
{
LargeObject glo;
// do some initialization stuff with glo
return glo;
}
void test()
{
LargeObject tlo = getLargeObject();
// do sth. with tlo;
}
A simple compiler would create a local LargeObject glo on the getLargeObject() stack and then assign it to tlo in test() when returning, which involves a copy operation.
But shouldn't a clever compiler realize that glo is going to be assigned to tlo and thus just use tlo's memory in the first place to avoid the copy operation? Resulting in something (functionally) like:
void getLargeObject(LargeObject &lo)
{
// do init stuff
}
void test()
{
LargeObject lo;
getLargeObject(lo);
}
My guess is, that compilers do something similar. But can it always be done? Are there situations where it can't be optimized like that? How can I know if my return value is copied or not?
Upvotes: 1
Views: 275
Reputation: 153919
For starters, even a naïve compiler will not “assign to
tlo”, since the standard doesn't allow it. The formal semantics
of your code involves two copies (both using the copy constructor); the
first from glo
to a temporary return value, and the second from this
temporary return value to tlo
. The standard, however, formally gives
compilers the right to eliminate both of these copies, in this specific
case, and practically speaking, I imagine that all compilers do.
The first copy can be suppressed anytime you return a local variable or
a temporary; some compilers don't do it if there is more than one
return
in the code, however (but that will never be the case in well
written code).
The suppression of the second copy depends on the fact that you are
constructing a new object at the call site. If you're not constructing
a new object, then there may not even be a second copy to suppress; e.g.
in a case like getLargeObject().memberFunction()
. If you're assigning
to an existing object, however, there's not much the compiler can do; it
must call the assignment operator. If the assignment operator copies,
then you get that copy.
Upvotes: 2
Reputation: 103703
Your guess is correct. And yes, there are situations where it cannot be done, for example:
LargeObject getLargeObject()
{
LargeObject glo1, glo2;
// do some initialization stuff
if (rand() % 2)
return glo1;
return glo2;
}
It can't be done there because the compiler can't know whether it will use glo1 or glo2 for the return value.
"How can I know if my return value is copied or not?"
Two ways I can think of. You could create noisy copy constructors. That is, copy constructors that have some detectable side effect, like printing a message. Then of course there's the old look at the assembly.
Upvotes: 4
Reputation: 2326
Yes it should. This is called the named returned value optimization (NRVO or just RVO).
Upvotes: 2