What you are seeing is undefined behaviour. It is fairly likely that, since the function you call does not depend on the object's state or vtable at all, the compiler inlined it to cout << boolalpha << ( 1+2 );
, so it does not matter whether or not the object has been destroyed - in fact, the compiler may not have even bothered to create it in the first place.
For example, with VS2010, in 'Debug' it calls F
and True
as static calls. As True
does not reference this
the code in it happens to work fine. ( it may even still work even if it did, as there are no member variables in C
to access, so the only thing it could do would be to print out the address of this
, and that would just be an address on the stack. If C
had member variables which were altered by C
's destructor and True
used them, then you would see a difference - in all cases, the behaviour is undefined and just an artefact of the implementation )
In 'Release' VS2010 does not bother to create any C
object or call F
or True
- it simply calls cout << boolalpha << 3
, having determined the value of C::True(2)
at compile time. There is no temporary C
object, invalid or not, in the program the compiler generates.
So just because calling a function on an object appears to work, it does not imply that the object exists, or ever existed, in the program generated by the compiler. A different source program with different undefined behaviour may cause the compiler to generate a executable which raises an access violation, or exhibit some other behaviour.
The binding a return value to const reference only applies to return by value, not returning a reference to a parameter or local, otherwise the compiler would need to solve the halting problem to determine the lifecycle of objects.
For example, this code:
#include<iostream>
class C
{
public:
int t;
C( int t ) : t(t){}
~C() { std::cout << __FUNCTION__ << " " << t << std::endl; }
};
const C& F(const C& c)
{
return c;
}
const C& G()
{
return C(2);
}
C H()
{
return C(3);
}
int main()
{
const C& c = F(C(1));
std::cout << "main 1" << std::endl;
const C& d = G();
std::cout << "main 2" << std::endl;
const C& e = H();
std::cout << "main 3" << std::endl;
}
results in this output - only H()
returns by value, so only the 3rd C has its lifecycle extended:
C::~C 1
main 1
C::~C 2
main 2
main 3
C::~C 3