Reputation: 1136
I have looked at different sources with regard to the internal implementation of auto_ptr<> and auto_ptr_ref<>. I have this question that I couldn't figure out why.
.... When returning a 'auto_ptr' from a function, the compiler finds that there is no suitable ctor to copy construct the returned object. But there is conversion to 'auto_ptr_ref' and ctor taking an 'auto_ptr_ref' constructing an 'auto_ptr'. Thus, the compiler creates an 'auto_ptr_ref' which basically just holds a reference to the original 'auto_ptr' and then constructs an 'auto_ptr' from this object. That's all (well, when returning an object, the compiler goes through this process normally twice because the returned value is copied somewhere but this does not change the process).... (Reference http://www.josuttis.com/libbook/auto_ptr.html)
In this example, I emulate the implementation of auto_ptr<> and auto_ptr_ref<> and is able to generate results showing that compiler indeed goes through the process twice
The example has these basic traits:
1) A's copy constructor does NOT take const reference. 2) A has conversion operator B 3) A has constructor A(B);
class B {
};
class A {
public:
A () {
printf("A default constructor() @ %p\r\n", this);
}
A(B) {
printf("constructor(B) @ %p\r\n", this);
}
A (A &a) {
printf("copy constructor(non-const) @ %p\r\n", this);
}
operator B() {
printf("A convertion constructor(B) @ %p\r\n", this);
return B();
}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
}
So when A a(foo())) is executed
1) foo() generates temporary object X 2) X is converted to type B 3) constructor A(B) is used to construct object a
This is output:
A default constructor() @ 0xbfea340f
A convertion constructor(B) @ 0xbfea340f
constructor(B) @ 0xbfea344f
A convertion constructor(B) @ 0xbfea344f
constructor(B) @ 0xbfea344e
We can see that compiler wen through the conversion-construct steps 2&3 twice.
Why is that?
Upvotes: 1
Views: 164
Reputation: 19721
If you are calling a function which returns a class type, basically the following happens:
On the call, the calling function reserves some space for the temporary return value on the stack (it has to be done by the calling function because anything the called function allocates on the stack gets deallocated as soon as the function returns). It passes the address of that space to the called function.
On executing the return
statement, the called function constructs the return value from the argument given to the return
statement into the space provided by the calling function. In your case, that argument is the temporary A
value.
After the function returns, the caller uses the temporary value the called function constructed to do whatever the code demands. In your case, you use it to construct a local variable from it.
So you construct a new object of type A
from an existing one twice: First, to construct the temporary return value (whose life time persists after the function foo
returns, until the end of the declaration) from the explicitly generated temporary in the return statement (whole lifetime ends on the end of the full expression, that is in this case equivalent to on return from foo
). And second, to initialize the local variable a
from the temporary returned by foo
.
Of course, due to no appropriate copy constructor being available, in both cases you go through the B
conversions. This works because the return
does a direct initialization, and for a
you explicitly coded such a direct initialization.
Upvotes: 1
Reputation: 21113
Class A
is being created 3 times. Once as a temporary, and copied twice. Other compilers might return different results, based on their optimization settings.
return A()
creates a temporary A
, and then copies it to the returned A
This first copy is the first time that you see steps 2 and 3.
Then A a(foo());
copies the return from foo()
into the variable in main. Triggering steps 2 and 3 again.
Upvotes: 0