This topic is 4811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

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.

Share on other sites
Quote:
 Original post by neverlandThe 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] );

Share on other sites
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 <code>new</code>

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;}

1. 1
2. 2
Rutin
19
3. 3
4. 4
5. 5

• 9
• 9
• 9
• 14
• 12
• Forum Statistics

• Total Topics
633295
• Total Posts
3011245
• Who's Online (See full list)

There are no registered users currently online

×