Possible Duplicate:
Can a local variable’s memory be accessed outside its scope?
Code:
#include <iostream>
using namespace std;
class B{
public:
int b;
B():b(1){}
~B(){cout << "Destructor ~B() " << endl;}
};
class A{
public:
B ob;
A()try{throw 4;}
catch(...){cout << "Catched in A() handler : ob.b= " << ob.b<<endl;}
};
int main()try{
A t;
}
catch(...){cout << "CATCHED in Main" << endl;}
Output:
Destructor ~B()
Catched in A() handler : ob.b= 1
CATCHED in Main
My Question is how it's possible to access a member variable b
of an object ob
that its destructor call finished.
Because while the object has been destroyed, the actual memory that it occupied still exists. However, it's undefined behavior, and may or may not work.
Using a destructed object is undefined behaviour. This means that you may be getting this behaviour now, but nothing guarantees that you will get it some other time. Undefined behaviour is more dangerous than a regular bug because it can be more difficult to detect, as this example shows.
UPDATE: Following some comments, I'll explain why OP's code produces that output.
try
function blocks are a somewhat obscure feature in C++. You can surround the whole body of a function inside a try
block, with its corresponding catch
. This is, instead of:
void foo()
{
try
{
//...
}
catch (/*whatever*/)
{
//...
}
}
You can write:
void foo()
try
{
//...
}
catch (/*whatever*/)
{
//...
}
This is not too useful, really, but can be marginally useful for constructors, because this is the only way to include the initialisation list inside the try
block. Thus, OP's code for the A
constructor is equivalent to:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
}
I said this is just marginally useful because you cannot use the object you are constructing inside the catch
block; if you throw inside the try
block, the exception will leave the constructor body, so the object will have never been constructed and any constructed data member will be immediately destructed before entering the catch
block. But it might have some use for logging purposes.
Now, as we all know, a constructor (asuming we are not using the nothrow
version) can only do two things:
- Return a constructed object
- Throw an exception
In this constructor we throw, but the exception is caught in the catch
block. So what happens now? What will be returned to the code calling the constructor? We cannot return a constructed object because we have none, so there is only one alternative: the catch
block must throw. And this is actually what the standard mandates in this case. If we do not throw explicitly, the compiler will silently add a throw;
instruction at the end of the catch
block. So, elaborating a bit more, the constructor is equivalent to the following:
A()
try
: b()
{
throw 4;
}
catch(...)
{
cout << "Catched in A() handler : ob.b= " << ob.b<<endl;
throw;
}
And this is the reason why the exception is caught twice: once in A
constructor and once in main()
.
That might be a bug in your compiler.
When I ran your code, the destructor is called in the proper order. The output is:
Catched in A() handler : ob.b= 1
Destructor ~B()
And I can't imagine any reason why catch
in main
is executed. The exception was already caught in A::A()
.
Update
I was confused by the edit. Originally, it was initializer list try/catch syntax which makes a difference. Now I can reproduce OP's output and it is UB indeed. I got a crash.