Topic: Can one do this in a handler???
Author: David Byrden <100101.2547@compuserve.com>
Date: 1996/02/05 Raw View
I am studying the problem of writing exception-safe code,and have
designed a small class which illustrates a technique of holding
exceptions in abeyance while you continue to do some cleanup work.
I wonder if anyone would examine the destructor of this class and tell
me whether they can see it violating the C++ standard; I have of course
examined that myself, but find it somewhat ambigous on the subject of
exceptions caught by the ellipsis.
This template class owns a block of heap memory. The memory is allocated
as an array of char; later, the placement "new" is used to construct T
objects in the memory block. The Ts are all placed contigously from the
start of the block, and the number of Ts in the block is remembered by a
data member in the class.
template< class T>
class Tblock
{
T* theBlock ; // Start of the memory block
int count ; // Number of T objects in it
Tblock() ;
~Tblock() ;
} ;
The interesting part is the Tblock destructor. The destructor of class T
is assumed to be able to throw exceptions, and I attempt to correctly
destroy the Tblock object even when that happens.
template< class T >
Tblock<T>::~Tblock( )
{
try
{
for( count-- ; count >= 0 ; count-- )
theBlock[count].~T() ; // [a]
delete [ ] static_cast<char*> theBlock ;
}
catch( ... )
{
~Tblock( ) ; // [b]
throw ;
}
}
Notes:
1 [a] and [b] are explicit destructor calls. I assume that this syntax
is correct because of the example of an explicit destructor call in
CopyConstructible Requirements 20.1.3.1
2 The intention is that the destructor shall explicitly destroy each T
object with an explicit destructor call, working down from the
highest-numbered T in the block to zero.
3 Any T may throw any exception from its destructor. In that case, we
go to the catch block and catch it with the intention of rethrowing
it later.
4 The catch handler in the destructor explicitly calls the destructor
itself. The intended effect of this is that the counter shall
continue downwards, destroying the remaining T objects, while the
exception from the bad one remains in abeyance, waiting to be
rethrown.
5 The destructor call is recursive. Any and all of the T objects may
throw from its destructor, and yet the "good" ones will all be
destroyed,and finally the memory will be deleted. If exceptions
are thrown by any T objects, the most recently thrown one will
propagate out of the Tblock dtor.
6 Incidentally, it is illegal to remove the outermost brackets and make
the whole thing a function-try-block, because calling the destructor
from the handler would result in undefined behaviour.
Thankyou
David
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
]