16.2 Programming Techniques for Exception Handling

Only use this in exceptional circumstances.

WARREN PEACE, The Lieutenant’s Tools

So far, we have shown you lots of code that explains how exception handling works in C++, but we have not yet shown even one example of a program that makes good and realistic use of exception handling. However, now that you know the mechanics of exception handling, this section can go on to explain exception-handling techniques.

When to Throw an Exception

We have given some very simple code in order to illustrate the basic concepts of exception handling. However, our examples were unrealistically simple. A more complicated but better guideline is to separate throwing an exception and catching the exception into separate functions. In most cases, you should include any throw statement within a function definition, list the exception in the exception specification for that function, and place the catch clause in a different function. Thus, the preferred use of the try-throw-catch triad is as illustrated here:

void functionA() throw (MyException)
{
        .
        .
        .
    throw MyException(<Maybe an argument>);
        .
        .
        .
}

Then, in some other function (perhaps even some other function in some other file), you have

void functionB()
{
        .
        .
        .
   try
   {
        .
        .
        .
     functionA();
        .
        .
        .
    }
     catch(MyException e)
    {
        <Handle exception>
    }
        .
        .
        .
}

Moreover, even this kind of use of a throw statement should be reserved for cases in which it is unavoidable. If you can easily handle a problem in some other way, do not throw an exception. Reserve throw statements for situations in which the way the exceptional condition is handled depends on how and where the function is used. If the way that the exceptional condition is handled depends on how and where the function is invoked, then the best

thing to do is to let the programmer who invokes the function handle the exception. In all other situations, it is almost always preferable to avoid throwing exceptions.

Exception Class Hierarchies

It can be very useful to define a hierarchy of exception classes. For example, you might have an ArithmeticError exception class and then define an exception class DivideByZeroError that is a derived class of ArithmeticError. Since a DivideByZeroError is an ArithmeticError, every catch block for an ArithmeticError will catch a DivideByZeroError. If you list ArithmeticError in an exception specification, then you have, in effect, also added DivideByZeroError to the exception specification, whether or not you list DivideByZeroError by name in the exception specification.

Testing for Available Memory

In Chapter 13, we created new dynamic variables with code such as the following:

struct Node
{
    int data;
    Node *link;
};
typedef Node* NodePtr;
    . . .
NodePtr pointer = new Node;

This works fine as long as there is sufficient memory available to create the new node. But, what happens if there is not sufficient memory? If there is not sufficient memory to create the node, then a bad_alloc exception is thrown. The type bad_alloc is part of the C++ language. You do not need to define it.

Since new will throw a bad_alloc exception when there is not enough memory to create the node, you can check for running out of memory as follows:

try
{
    NodePtr pointer = new Node;
}
catch (badAlloc)
{
    cout << "Ran out of memory!";
}

Of course, you can do other things besides simply giving a warning message, but the details of what you do will depend on your particular programming task.

Rethrowing an Exception

It is legal to throw an exception within a catch block. In rare cases, you may want to catch an exception and then, depending on the details, decide to throw the same or a different exception for handling farther up the chain of exception-handling blocks.

Self-Test Exercises

  1. What happens when an exception is never caught?

  2. Can you nest a try block inside another try block?