Exception, delete doesn't call destructor in catch block???

I don't understand why delete doesn't call a destructor in a catch block, because i want to clean up if something goes wrong?
I have created minimalistic test app:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <Windows.h>
#include <iostream>
#include <exception>

class Foo
{
private:
	int* data;
public:
	Foo()
	{
		data = new int;
		*data = 5;
                // imagine there is something wrong happend and i call throw
		throw std::exception("EXCEPT");
	}
	~Foo()
	{
		delete data;
		data = nullptr;
	}
};

int main()
{
	Foo* pFoo = nullptr;
	try
	{
		pFoo = new Foo;
	}
	catch(const std::exception& e)
	{
		MessageBox(0, e.what(), "Exception", 0);
		delete pFoo;// this doesn't call's Foo destructor???
		return -1;
	}

	delete pFoo;

	std::cout << "Press enter to exit...";
	std::cin.get();
	return 0;
}


Thanks for your time.
Last edited on
Take a look more closely at this:

 
pFoo = new Foo;


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
	}
};
Great explanation, thanks for tips.
Topic archived. No new replies allowed.