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
]