Re: exception handling problem
asm23 <asmwarrior@gmail.com> kirjutas:
Hi, everyone, I'm learning <<thinking c++>> volume Two, and testing
the code below.
///////////////////////////////////////////////////////////////////////
////// //: C01:Wrapped.cpp
#include <iostream>
#include <cstddef>
using namespace std;
template<class T, int sz = 1> class PWrap {
T* ptr;
public:
class RangeError {}; // Exception class
PWrap() {
ptr = new T[sz];
cout << "PWrap constructor" << endl;
}
~PWrap() {
delete[] ptr;
cout << "PWrap destructor" << endl;
}
T& operator[](int i) throw(RangeError) {
if(i >= 0 && i < sz) return ptr[i];
throw RangeError();
}
};
class Cat {
public:
Cat() { cout << "Cat()" << endl; }
~Cat() { cout << "~Cat()" << endl; }
void g() {}
};
class Dog {
public:
void* operator new[](size_t) {
cout << "Allocating a Dog" << endl;
//throw 47; //*******************************NOTE
return 0;
}
void operator delete[](void* p) {
cout << "Deallocating a Dog" << endl;
::delete[](p);
}
};
class UseResources {
PWrap<Cat, 3> cats;
PWrap<Dog> dog;
public:
UseResources() {
cout << "UseResources()" << endl;
}
~UseResources() {
cout << "~UseResources()" << endl;
}
void f() { cats[1].g(); }
};
int main() {
try {
UseResources ur;
} catch(int) {
cout << "inside handler" << endl;
} catch(...) {
cout << "inside catch(...)" << endl;
}
}
///////////////////////////////////////////////////////////////////////
////////// In the UseResources class, It will create *Three cats* and
*One dog*, When I comment the "throw 47" line in the class Dog
implementation. it has the result output:
=================================
Cat()
Cat()
Cat()
PWrap constructor
Allocating a Dog
PWrap constructor
UseResources()
~UseResources()
Deallocating a Dog
PWrap destructor
~Cat()
~Cat()
~Cat()
PWrap destructor
==================================
But When I uncomment the "throw 47" line, the result will be:
=================================
Cat()
Cat()
Cat()
PWrap constructor
Allocating a Dog
~Cat()
~Cat()
~Cat()
PWrap destructor
inside handler
==================================
It seems that an exception happened when we are create the Dog object.
My Question:
When an exception occurred in the allocate a Dog object,
Why was *~UseResources()* not called?
Why was *~Cat()* called?
In general, everything which has been constructed will be destructed.
Something is considered constructed when its constructor completes. The
Cats and their PWrap constructors were completed, so they were destructed
as well. The Dog, its PWrap and UseResources constructors were not
completed, so their destructors were not called.
Note that because each your class wraps at most only one potentially
failing resource allocation (a good design!), everything gets cleaned up
automagically, no memory leaks etc.
How does the "exception mechanism" guarantee that the allocated object
will be cleared.
It's the task for compiler writers, do not worry about this.
Someone can give this a brief trick? Is it about call stack unwinding?
Thank you very much.
Stack unwinding is about different objects in a stack frame, but here the
issue is about subobjects of a complex object, which is slightly
different.
I would say this is more of the class invariants. The destructor is
entitled to expect the object in a good shape, i.e. class invariant
holding. If the constructor did not complete, there is no guarantee that
the class invariant holds, thus the destructor cannot be called.
hth
Paavo