Reputation: 39
Look at this code:
class Test
{
//
};
Test TestAddress()
{
Test test;
cout << "Object Address in function: " << (int)&test << endl;
return test;
}
int IntAddress()
{
int test;
cout << "Integer Address in function: " <<(int)&test << endl;
return test;
}
int main() {
int x = IntAddress();
cout << "Integer Address in Main: " <<(int)&x << endl;
Test object = TestAddress();
cout << "Object Address in Main: " <<(int)&object << endl;
return 0;
}
The output is:
Integer Address in function: 1076679252
Integer Address in Main: 1076679220
Object Address in function: 1076679221
Object Address in function: 1076679221
Could someone explain me why is that, when I'm returning an object by value I receive the same addresses in function and main. But when I do the same thing with an Integer, the adressess are different?
Upvotes: 2
Views: 131
Reputation: 596307
First, you don't need to cast your pointers to int
, as operator<<()
has an overload that accepts a void*
for printing pointer addresses. Any pointer can be passed to <<
without casting (unless there is a specialized overload present for that pointer type, like the one for char*
, in which case you should cast to void*
instead of int
).
Second, most compilers implement Return Value Optimization when a function returns an object by value (RVO is not used for primitive types, as copies are cheap). So your code is essentially acting more like this behind the scenes:
void TestAddress(Test &result)
{
cout << "Object Address in function: " << &result << endl;
}
int main()
{
//...
Test object;
TestAddress(object);
cout << "Object Address in Main: " << &object << endl;
return 0;
}
Or even this:
void TestAddress(Test &result)
{
new (&result) Test(); // <-- constructor called here instead!
cout << "Object Address in function: " << &result << endl;
}
int main()
{
//...
Test object; // <-- constructor not called here!
TestAddress(object);
cout << "Object Address in Main: " << &object << endl;
return 0;
}
Either way, the compiler is smart enough to know that the temp object inside the function is going to end up in the caller's object, so it eliminates the temp and acts on the caller's object directly instead.
That is why you see the same memory address being reported by two output statements seemingly acting on two separate objects - they are actually the same object in memory when RVO is being used.
Upvotes: 1
Reputation: 20730
The so called "automatic variables" are allocated on the stack. The moment of their allocation can be subject to compiler optimization.
When a local variable is returned by value, the compiler has essentially two choices:
=
in the caller, copy the temporary into the caller receiving constructing variable.Or, it can:
Now, since the cost to "copy an integer" and of "dereferece an integer" in term of CPU processing are in favor of the copy (an int is the CPU primitive number type), and since "temporary integer" can fit a CPU register (so it's not a "copy to memory) the compiler use the first method for int's.
Since a class can have whatever size (and copy may have higher cost), the compiler can decide do adopt the second method.
In any case, you should not care about that: the external observable behavior will be the same, since the access to the external and internal variables are mutually exclusive.
Upvotes: 3
Reputation: 3312
I think that your compiler is applying return value optimization, where main()
and TestAddress()
are acting on the same object variable in memory.
Upvotes: 5
Reputation: 6112
Wyjun,
When you return an object by value, both of those objects contain the same pointer. However, when you return a primitive by value, the primitive within the function scope is destroyed, it's value already being contained in the callee's stack frame, and that value will be reallocated to a new memory space.
Please let me know if you have any questions!
Thank you for your time,
Upvotes: 0