Take a look more closely at this:
This line actually does several things, in order:
1) Allocate space for a Foo
2) Construct the Foo object
3) Assign a pointer to the constructed Foo object to pFoo
Since an exception is being thrown in Foo's constructor, that means it's being thrown on step 2. Therefore step 3 never occurs. As a result, pFoo is left as a null pointer when you try to delete it.
However,
this is a good thing. If Foo's ctor throws an exception it means that the object has not been completely constructed, and destructing a partially constructed object would be very dangerous.
If you want your constructor to be exception safe to prevent leaks, you'll either need to put in a try/catch, or use some kind of RAII object to manage the dynamic memory.
1 2 3 4 5 6
|
Foo()
{
data = new int;
*data = 5;
throw std::exception("EXCEPT"); // bad, leaks 'data'
}
| |
1 2 3 4 5 6 7 8 9 10 11 12
|
Foo()
{
data = new int;
*data = 5;
try{
throw std::exception("EXCEPT");
}catch(...)
{
delete data; // no longer leaks
throw;
}
}
| |
Of course, the RAII approach is simpler:
1 2 3 4 5 6 7 8 9 10 11 12
|
class Foo
{
private:
std::auto_ptr<int> data;
public:
Foo() : data(new int)
{
*data = 5;
throw std::exception("EXCEPT");
// no worry about a leak, auto_ptr's dtor will clean up for you
}
};
| |