Destructors That Throw Exceptions


Exceptions propagating from destructors cause a number of problems. For example, consider a Whole that holds pointers to a PartOne, a PartTwo, and a PartThree that it owns (i.e., it must delete them). If the destructors of the parts propagate exceptions, we would have trouble just writing a destructor for Whole. If more than one destructor throws, we must suppress at least one exception while remembering to destroy the third part. Writing update member functions (like assignment) under such circumstances is prohibitively difficult or impossible. There are many situations where an exception propagating from a destructor is extremely inconvenient — some are mentioned in the text. Another example is that objects with such behavior cannot be aggregated. (Even an array of two such objects is lethal if both destructors actually throw.) My advice is not to allow classes that behave in this manner into your system. (If forced to, you can always “wrap” them in a well behaved class of your own.)

If you look at the standard library containers, you’ll find that they place certain requirements on the types that are supplied as template parameters. One of these is that the destructor doesn’t throw exceptions (and this guarantee is provided by all classes in the standard library). There is a good reason for this: it is hard to write code that manipulates objects if those objects throw exceptions when you try to destroy them. In many cases, it is impossible to write efficient code under such circumstances. In addition, the C++ exception-handling mechanism itself objects to destructors propagating exceptions during the “stack unwinding” process. Indeed, unless the application developer takes extraordinary precautions, the application will be terminated in a graceless manner.

There is no advantage in allowing destructors to propagate exceptions and a whole host of disadvantages. Preventing destructors from throwing should be easy to achieve: in most cases all a destructor should be doing is destroying other objects whose destructors shouldn’t throw, or releasing resources — and if that fails an exception won’t help. Apart from the practicalities, what does an exception from a destructor mean? If a user tries to destroy an object and this fails, what is he supposed to do? Try again? Destructors that throw exceptions? Just say no.