Exceptions Inside Exceptions

One of the risks that we incur when working with exceptions, is having to control what is happening when the exception is received in the catch block.

An exception is thrown, as we have seen in the article about exceptions when the keyword throw is used. Then, a new object of the type determining the exception is created. For example, we can create a new exception in the following way:

void Obj::AMethod() {
   // ....
   if (error)
      throw new MyCustomException("something bad happened");
}

An exception is catch by a catch block that can be added to any code surrounding the place where the exception was thrown. Surrounding here means not only the code that directly throws the exception, but also any code that called the method where the exception is being thrown.

Here is an example:

void Obj::Example() {
   try {
   // ...
      this->AMethod();
   } catch (MyCustomException &e) {
      // process the exception here
   }
}

The main problem we are concerned about here is what happens between the moment the exception is thrown and the moment the program can restart on the catch block.

The main problem with catching exceptions, is that we need to make sure that no additional exceptions will be thrown during the process of destroying objects. For example, if the code above has an object with a destructor that throws another exception, then we have a problem.

Notice that, when throwing an exception, C++ maintains a context, which determines what destructor will be called in response to the exception. The fact is that all objects created in the context between the place where an exception was thrown until the catch block need to be destroyed.

If we send an exception during the destruction process, then C++ can become confused about what objects needs to be destroyed as a result. It is as if there were are double queue of objects that need to have their destructor called.

In such a situation, C++ won’t know what to do, and the program will simply stop working correctly and crash.

To avoid problems like this, the main suggestion is that we should avoid throwing exceptions on a destructor. We never know in what context a destructor will be called, so it is better to avoid throwing exception on any destructor.