Skip to main content
gamedev.net
🔒 Locked

a question about exception

Started by neverland Sep 12, 2005 at 3:10 AM 1 replies 700+ views
Original Post
neverland
neverland
When an exception thrown, all the objects successfully constructed in the try block will be destroyed. But consider the following code:
#include <iostream>
using namespace std;

class A {
public:
	A() throw(int) {
		ID = count++;
		cout << "object ID:" << ID << " generated." << endl;	
		if (3 == ID)
			throw 0;	
	}
	~A() {
		cout << "object ID:" << ID << " destroyed." << endl;
	}
	
private:
	static int count;
	int ID;
};
int A::count = 0;

int main()
{
	try {
		A *a1 = new A;
		A *a2 = new A;
		A *a3 = new A[3];
		
		delete a1;
		delete a2;
		delete[] a3;
		
		cout << "Exit Now" << endl;
	} catch(int) {
		cout << "exception caught" << endl;
	}
}
The output is: object ID:0 generated. object ID:1 generated. object ID:2 generated. object ID:3 generated. object ID:2 destroyed. exception caught The first element in the a3 array is successfully destroyed but a1 and a2 not. Why? If I change the try block to the following code:
try {
	A a1;
	A a2;
	A *a3 = new A[3];
		
	delete[] a3;
		
	cout << "Exit Now" << endl;
}
The output is: object ID:0 generated. object ID:1 generated. object ID:2 generated. object ID:3 generated. object ID:2 destroyed. object ID:1 destroyed. object ID:0 destroyed. exception caught a1 and a2 are successfully destroyed. I am a little bit confused.
MaulingMonkey
MaulingMonkey
Quote:
Original post by neverland
The first element in the a3 array is successfully destroyed but a1 and a2 not. Why?


Because when the exception is thrown, all "local" variables are destroyed (the pointers, but not the point-ees) and then the code proceeds immediately to the catch() statement - the delete statements are never reached.

Also, you'll note that a3[0] is successfully created - your code throws attempting to construct a3[1]. In the interests of exception-safety, new[] backs out (deconstructs) a3[0] as well - there's no mechanism for dealing with partially constructed arrays.

If you want these objects destroyed (and you probably do) you need to use RAII. The standard library has a "smart pointer" called std::auto_ptr which should clean up all the normal pointers:

std::auto_ptr< A > a1( new A );
std::auto_ptr< A > a2( new A );

note: auto_ptr does NOT work with arrays because it uses delete instead of delete[]. It also has weird copying semantics - "copying" (misdominer) causes the "ownership" to be "transfered". A useful alternative to protect yourself from accidentally transfering ownership would be:

boost::scoped_ptr< A > a1( new A );

(see boost homepage). Boost also has an array equivilant to scoped_ptr:

boost::scoped_array< A > a3( new A[3] );
trevaaar
trevaaar
The problem you're having is that in the first version, the variables are not on the stack. A variable on the stack (A someVariable) will be destroyed automatically when it goes out of scope (i.e. at the end of the try block or when an exception is thrown), whereas variables created on the heap (A* someVariable = new A;) must be deleted manually. Try this instead if you want to use the stack:

int main(){    try    {        A a1;        A a2;        A a3[3];        cout << "Exit Now" << endl;    }    catch(int)    {        cout << "Exception caught" << endl;    }    return 0;}


Or this version if you want to dynamically allocate the objects with new

int main(){    A* a1 = NULL;    A* a2 = NULL;    A* a3 = NULL;    try    {        a1 = new A;        a2 = new A;        a3 = new A[3];                cout << "Exit Now" << endl;    }    catch(int)    {        cout << "Exception caught" << endl;    }    delete[] a3; // if the creation failed, this will    delete a2; // have no effect because the variables    delete a1; // were initialized to NULL    return 0;}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.