Given the following code:
#include <iostream>
struct implicit_t
{
implicit_t(int x) :
x_m(x)
{
std::cout << "ctor" << std::endl;
}
~implicit_t()
{
std::cout << "dtor" << std::endl;
}
int x_m;
};
std::ostream& operator<<(std::ostream& s, const implicit_t& x)
{
return s << x.x_m;
}
const implicit_t& f(const implicit_t& x)
{
return x;
}
int main()
{
std::cout << f(42) << std::endl;
return 0;
}
I get the following output:
ctor
42
dtor
While I know this is correct, I'm not certain why. Is there anyone with stdc++ knowledge who can explain it to me?
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. [12.2/3]
12.2 Temporary objects, clause 3: "Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created."
1.9 Program execution, clause 12: "A full-expression is an expression that is not a subexpression of another expression."
Since there is a constructor which can accept the argument passed into the F() function the complier creates the object on the fly before putting the arguments on the stack. As can be see in the disassembly below. literal numbers are treated by default as ints so there is an acceptable conversion.
001115C5 call implicit_t::implicit_t (11112Ch)
001115CA mov dword ptr [ebp-4],0
001115D1 mov esi,esp
001115D3 mov eax,dword ptr [__imp_std::endl (11A308h)]
001115D8 push eax
001115D9 lea ecx,[ebp-0D4h]
001115DF push ecx
001115E0 call f (111113h)
Your temp object hangs around until the expression is fully evaluated. this can be made more evident if you add another call to your function.
int main()
{
std::cout << f(42) << std::endl;
std::cout <<f(80) << std::endl;
return 0;
}
Which has an output of
ctor
42
dtor
ctor
80
dtor
f(42)
constructs an unnamed implicit_t
implicitly. It lives for the duration of it's containing scope, just as any auto
variable would. Naturally, the d'tor gets called on return 0;
of main()
.