Chapter 8: Exceptions

Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.

Please state the document version you're referring to, as found in the title (in this document: 7.0.0) and please state chapter and paragraph name or number you're referring to.

All received mail is processed conscientiously, and received suggestions for improvements will usually have been processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.

C supports several ways in which a program can react to situations which break the normal unhampered flow of the program:

In C++ all the above ways to handle flow-breaking situations are still available. However, of the mentioned alternatives, the setjmp() and longjmp() approach isn't frequently seen in C++ (or even in C) programs, due to the fact that the program flow is completely disrupted.

C++ offers exceptions as the preferred alternative to setjmp() and longjmp() are. Exceptions allow C++ programs to perform a controlled non-local return, without the disadvantages of longjmp() and setjmp().

Exceptions are the proper way to bail out of a situation which cannot be handled easily by a function itself, but which is not disastrous enough for a program to terminate completely. Also, exceptions provide a flexible layer of control between the short-range return and the crude exit().

In this chapter exceptions and their syntax will be introduced. First an example of the different impacts exceptions and setjmp() and longjmp() have on a program will be given. Then the discussion will dig into the formalities exceptions.

8.1: Using exceptions: syntax elements

With exceptions the following syntactical elements are used:

8.2: An example using exceptions

In the next two sections the same basic program will be used. The program uses two classes, Outer and Inner. An Outer object is created in main(), and its member Outer::fun() is called. Then, in Outer::fun() an Inner object is constructed. Having constructing the Inner object, its member Inner::fun() is called.

That's about it. The function Outer::fun() terminates, and the destructor of the Inner object is called. Then the program terminates and the destructor of the Outer object is called. Here is the basic program:

    #include <iostream>
    using namespace std;

    class Inner
    {
        public:
            Inner();
            ~Inner();
            void fun();
    };

    class Outer
    {
        public:
            Outer();
            ~Outer();
            void fun();
    };

    Inner::Inner()
    {
        cout << "Inner constructor\n";
    }

    Inner::~Inner()
    {
        cout << "Inner destructor\n";
    }

    void Inner::fun()
    {
        cout << "Inner fun\n";
    }

    Outer::Outer()
    {
        cout << "Outer constructor\n";
    }

    Outer::~Outer()
    {
        cout << "Outer destructor\n";
    }

    void Outer::fun()
    {
        Inner in;

        cout << "Outer fun\n";
        in.fun();
    }

    int main()
    {
        Outer out;

        out.fun();
    }

    /*
        Generated output:
    Outer constructor
    Inner constructor
    Outer fun
    Inner fun
    Inner destructor
    Outer destructor
    */
After compiling and running, the program's output is entirely as expected, and it shows exactly what we want: the destructors are called in their correct order, reversing the calling sequence of the constructors.

Now let's focus our attention on two variants, in which we simulate a non-fatal disastrous event to take place in the Inner::fun() function, which is supposedly handled somewhere at the end of the function main(). We'll consider two variants. The first variant will try to handle this situation using setjmp() and longjmp(); the second variant will try to handle this situation using C++'s exception mechanism.

8.2.1: Anachronisms: `setjmp()' and `longjmp()'

In order to use setjmp() and longjmp() the basic program from section 8.2 is slightly modified to contain a variable jmp_buf jmpBuf. The function Inner::fun() now calls longjmp, simulating a disastrous event, to be handled at the end of the function main(). In main() we see the standard code defining the target location of the long jump, using the function setjmp(). A zero return value indicates the initialization of the jmp_buf variable, upon which the Outer::fun() function is called. This situation represents the `normal flow'.

To complete the simulation, the return value of the program is zero only if the program is able to return from the function Outer::fun() normally. However, as we know, this won't happen: Inner::fun() calls longjmp(), returning to the setjmp() function, which (at this time) will not return a zero return value. Hence, after calling Inner::fun() from Outer::fun() the program proceeds beyond the if-statement in the main() function, and the program terminates with the return value 1. Now try to follow these steps by studying the following program source, modified after the basic program given in section 8.2:

    #include <iostream>
    #include <setjmp.h>
    #include <cstdlib>

    using namespace std;

    class Inner
    {
        public:
            Inner();
            ~Inner();
            void fun();
    };

    class Outer
    {
        public:
            Outer();
            ~Outer();
            void fun();
    };

    jmp_buf jmpBuf;

    Inner::Inner()
    {
        cout << "Inner constructor\n";
    }

    void Inner::fun()
    {
        cout << "Inner fun()\n";
        longjmp(jmpBuf, 0);
    }

    Inner::~Inner()
    {
        cout << "Inner destructor\n";
    }

    Outer::Outer()
    {
        cout << "Outer constructor\n";
    }

    Outer::~Outer()
    {
        cout << "Outer destructor\n";
    }

    void Outer::fun()
    {
        Inner in;

        cout << "Outer fun\n";
        in.fun();
    }

    int main()
    {
        Outer out;

        if (!setjmp(jmpBuf))
        {
            out.fun();
            return 0;
        }
        return 1;
    }
    /*
        Generated output:
    Outer constructor
    Inner constructor
    Outer fun
    Inner fun()
    Outer destructor
    */
The output produced by this program clearly shows that the destructor of the class Inner is not executed. This is a direct result of the non-local characteristic of the call to longjmp(): processing proceeds immediately from the longjmp() call in the member function Inner::fun() to the function setjmp() in main(). There, its return value is zero, so the program terminates with return value 1. What is important here is that the call to the destructor Inner::~Inner(), waiting to be executed at the end of Outer::fun(), is never reached.

As this example shows that the destructors of objects can easily be skipped when longjmp() and setjmp() are used, these function should be avoided completely in C++ programs.

8.2.2: Exceptions: the preferred alternative

In C++ exceptions are the best alternative to setjmp() and longjmp(). In this section an example using exceptions is presented. Again, the program is derived from the basic program, given in section 8.2:
    #include <iostream>
    using namespace std;

    class Inner
    {
        public:
            Inner();
            ~Inner();
            void fun();
    };

    class Outer
    {
        public:
            Outer();
            ~Outer();
            void fun();
    };

    Inner::Inner()
    {
        cout << "Inner constructor\n";
    }

    Inner::~Inner()
    {
        cout << "Inner destructor\n";
    }

    void Inner::fun()
    {
        cout << "Inner fun\n";
        throw 1;
        cout << "This statement is not executed\n";
    }

    Outer::Outer()
    {
        cout << "Outer constructor\n";
    }

    Outer::~Outer()
    {
        cout << "Outer destructor\n";
    }

    void Outer::fun()
    {
        Inner in;

        cout << "Outer fun\n";
        in.fun();
    }


    int main()
    {
        Outer out;

        try
        {
            out.fun();
        }
        catch (...)
        {}
    }
    /*
        Generated output:
    Outer constructor
    Inner constructor
    Outer fun
    Inner fun
    Inner destructor
    Outer destructor
    */
In this program an exception is thrown, where a longjmp() was used in the program in section 8.2.1. The comparable construct for the setjmp() call in that program is represented here by the try and catch blocks. The try block surrounds statements (including function calls) in which exceptions are thrown, the catch block may contain statements to be executed just after throwing an exception.

So, comparably to the example given in section 8.2.1, the function Inner::fun() terminates, albeit with an exception rather than by a call to longjmp(). The exception is caught in main(), and the program terminates. When the output from the current program is inspected, we notice that the destructor of the Inner object, created in Outer::fun() is now correctly called. Also notice that the execution of the function Inner::fun() really terminates at the throw statement: the insertion of the text into cout, just beyond the throw statement, doesn't take place.

Hopefully this has raised your appetite for exceptions, since it was shown that:

8.3: Throwing exceptions

Exceptions may be generated in a throw statement. The throw keyword is followed by an expression, resulting in a value of a certain type. For example:
    throw "Hello world";        // throws a char *
    throw 18;                   // throws an int
    throw string("hello");      // throws a string
Objects defined locally in functions are automatically destroyed once exceptions thrown by these functions leave these functions. However, if the object itself is thrown, the exception catcher receives a copy of the thrown object. This copy is constructed just before the local object is destroyed.

The next example illustrates this point. Within the function Object::fun() a local Object toThrow is created, which is thereupon thrown as an exception. The exception is caught outside of Object::fun(), in main(). At this point the thrown object doesn't actually exist anymore, Let's first take a look at the sourcetext:

    #include <iostream>
    #include <string>
    using namespace std;

    class Object
    {
        string d_name;

        public:
            Object(string name)
            :
                d_name(name)
            {
                cout << "Object constructor of " << d_name << "\n";
            }
            Object(Object const &other)
            :
                d_name(other.d_name + " (copy)")
            {
                cout << "Copy constructor for " << d_name << "\n";
            }
            ~Object()
            {
                cout << "Object destructor of " << d_name << "\n";
            }
            void fun()
            {
                Object toThrow("'local object'");

                cout << "Object fun() of " << d_name << "\n";
                throw toThrow;
            }
            void hello()
            {
                cout << "Hello by " << d_name << "\n";
            }
    };

    int main()
    {
        Object out("'main object'");

        try
        {
            out.fun();
        }
        catch (Object o)
        {
            cout << "Caught exception\n";
            o.hello();
        }
    }
    /*
        Generated output:
Object constructor of 'main object'
Object constructor of 'local object'
Object fun() of 'main object'
Copy constructor for 'local object' (copy)
Object destructor of 'local object'
Copy constructor for 'local object' (copy) (copy)
Caught exception
Hello by 'local object' (copy) (copy)
Object destructor of 'local object' (copy) (copy)
Object destructor of 'local object' (copy)
Object destructor of 'main object'
    */
The class Object defines several simple constructors and members. The copy constructor is special in that it adds the text " (copy)" to the received name, to allow us to monitor the construction and destruction of objects more closely. The member function Object::fun() generates the exception, and throws its locally defined object. Just before the exception the following output is generated by the program:
    Object constructor of 'main object'
    Object constructor of 'local object'
    Object fun() of 'main object'
Now the exception is generated, resulting in the next line of output:
    Copy constructor for 'local object' (copy)
The throw clause receives the local object, and treats it as a value argument: it creates a copy of the local object. Following this, the exception is processed: the local object is destroyed, and the catcher catches an Object, again a value parameter. Hence, another copy is created. Therefore, we see the following lines:
    Object destructor of 'local object'
    Copy constructor for 'local object' (copy) (copy)
Now we are inside the catcher, who displays its message:
    Caught exception
followed by the calling of the hello() member of the received object. This member also shows us that we received a copy of the copy of the local object of the Object::fun() member function:
    Hello by 'local object' (copy) (copy)
Finally the program terminates, and its still living objects are now destroyed in their reversed order of creation:
    Object destructor of 'local object' (copy) (copy)
    Object destructor of 'local object' (copy)
    Object destructor of 'main object'

If the catcher would have been implemented so as to receive a reference to an object (which you could do by using `catch (Object &o)'), then repeatedly calling the copy constructor would have been avoided. In that case the output of the program would have been:

    Object constructor of 'main object'
    Object constructor of 'local object'
    Object fun() of 'main object'
    Copy constructor for 'local object' (copy)
    Object destructor of 'local object'
    Caught exception
    Hello by 'local object' (copy)
    Object destructor of 'local object' (copy)
    Object destructor of 'main object'
This shows us that only a single copy of the local object has been used.

Of course, it's a bad idea to throw a pointer to a locally defined object: the pointer is thrown, but the object to which the pointer refers dies once the exception is thrown, and the catcher receives a wild pointer. Bad news....

Summarizing:

Exceptions are thrown in situations where a function can't continue its normal task anymore, although the program is still able to continue. Imagine a program which is an interactive calculator. The program continuously requests expressions, which are then evaluated. In this case the parsing of the expression may show syntactical errors; and the evaluation of the expression may result in expressions which can't be evaluated, e.g., because of the expression resulting in a division by zero. Also, the calculator might allow the use of variables, and the user might refer to non-existing variables: plenty of reasons for exceptions to be thrown, but no overwhelming reason to terminate the program. In the program, the following code may be used, all throwing exceptions:
    if (!parse(expressionBuffer))           // parsing failed
        throw "Syntax error in expression";

    if (!lookup(variableName))              // variable not found
        throw "Variable not defined";

    if (divisionByZero())                   // unable to do division
        throw "Division by zero is not defined";
The location of these throw statements is immaterial: they may be placed deeply nested within the program, or at a more superficial level. Furthermore, functions may be used to generate the expression which is then thrown. A function
        char const *formatMessage(char const *fmt, ...);
would allow us to throw more specific messages, like
    if (!lookup(variableName))
        throw formatMessage("Variable '%s' not defined", variableName);

8.3.1: The empty `throw' statement

Situations may occur in which it is required to inspect a thrown exception. Then, depending on the nature of the received exception, the program may continue its normal operation, or a serious event took place, requiring a more drastic reaction by the program. In a server-client situation the client may enter requests to the server into a queue. Every request placed in the queue is normally answered by the server, telling the client that the request was successfully completed, or that some sort of error has occurred. Actually, the server may have died, and the client should be able to discover this calamity, by not waiting indefinitely for the server to reply.

In this situation an intermediate exception handler is called for. A thrown exception is first inspected at the middle level. If possible it is processed there. If it is not possible to process the exception at the middle level, it is passed on, unaltered, to a more superficial level, where the really tough exceptions are handled.

By placing an empty throw statement in the code handling an exception the received exception is passed on to the next level that might be able to process that particular type of exception.

In our server-client situation a function

    initialExceptionHandler(char *exception)
could be designed to do so. The received message is inspected. If it's a simple message it's processed, otherwise the exception is passed on to an outer level. The implementation of initialExceptionHandler() shows the empty throw statement:
    void initialExceptionHandler(char *exception)
    {
        if (!plainMessage(exception))
            throw;

        handleTheMessage(exception);
    }
As we will see below (section 8.5), the empty throw statement passes on the exception received in a catch-block. Therefore, a function like initialExceptionHandler() can be used for a variety of thrown exceptions, as long as the argument used with initialExceptionHandler() is compatible with the nature of the received exception.

Does this sound intriguing? Then try to follow the next example, which jumps slightly ahead to the topics covered in chapter 14. The next example may be skipped, though, without loss of continuity.

We can now state that a basic exception handling class can be constructed from which specific exceptions are derived. Suppose we have a class Exception, containing a member function ExceptionType Exception::severity(). This member function tells us (little wonder!) the severity of a thrown exception. It might be Message, Warning, Mistake, Error or Fatal. Furthermore, depending on the severity, a thrown exception may contain less or more information, somehow processed by a function process(). In addition to this, all exceptions have a plain-text producing member function, e.g., toString(), telling us a bit more about the nature of the generated exception.

Using polymorphism, process() can be made to behave differently, depending on the nature of a thrown exception, when called through a basic Exception pointer or reference.

In this case, a program may throw any of these five types of exceptions. Let's assume that the Message and Warning exceptions are processable by our initialExceptionHandler(). Then its code would become:

    void initialExceptionHandler(Exception const *e)
    {
        cout << e->toString() << endl;  // show the plain-text information

        if
        (
            e->severity() != ExceptionWarning
            &&
            e->severity() != ExceptionMessage
        )
            throw;                      // Pass on other types of Exceptions

        e->process();               // Process a message or a warning
        delete e;
    }
Due to polymorphism (see chapter 14), e->process() will either process a Message or a Warning. Thrown exceptions are generated as follows:
    throw new Message(<arguments>);
    throw new Warning(<arguments>);
    throw new Mistake(<arguments>);
    throw new Error(<arguments>);
    throw new Fatal(<arguments>);
All of these exceptions are processable by our initialExceptionHandler(), which may decide to pass exceptions upward for further processing or to process exceptions itself. The polymorphic exception class is developed further in section 14.7.

8.4: The try block

The try-block surrounds statements in which exceptions may be thrown. As we have seen, the actual throw statement can be placed everywhere, not necessarily directly in the try-block. It may, for example, be placed in a function, called from within the try-block.

The keyword try is followed by a set of curly braces, acting like a standard C++ compound statement: multiple statements and definitions may be placed here.

It is possible (and very common) to create levels in which exceptions may be thrown. For example, main()'s code is surrounded by a try-block, forming an outer level in which exceptions can be handled. Within main()'s try-block, functions are called which may also contain try-blocks, forming the next level in which exceptions may be generated. As we have seen (in section 8.3.1), exceptions thrown in inner level try-blocks may or may not be processed at that level. By placing an empty throw in an exception handler, the thrown exception is passed on to the next (outer) level.

If an exception is thrown outside of any try-block, then the default way to handle (uncaught) exceptions is used, which is normally to abort the program. Try to compile and run the following tiny program, and see what happens:

    int main()
    {
        throw "hello";
    }

8.5: Catching exceptions

The catch block contains code that is executed when an exception is thrown. Since expressions are thrown, the catch-block must know what kind of exceptions it should be able to handle. Therefore, the keyword catch is followed by a parameter list consisting of but one parameter, which is the type of the exception handled by the catch block. So, an exception handler for char const * exceptions will have the following form:
    catch (char const *message)
    {
        // code to handle the message
    }
Earlier (section 8.3) we've seen that such a message doesn't have to be thrown as a static string. It's also possible for a function to return a string, which is then thrown as an exception. If such a function creates the string that is thrown as an exception dynamically, the exception handler will normally have to delete the allocated memory to prevent a memory leak.

Close attention should be paid to the nature of the parameter of the exception handler, to make sure that dynamically generated exceptions are deleted once the handler has processed them. Of course, when an exception is passed on to an outer level exception handler, the received exception should not be deleted by the inner level handler.

Different kinds of exceptions may be thrown: char *s, ints, pointers or references to objects, etc.: all these different types may be used in throwing and catching exceptions. So, various types of exceptions may come out of a try-block. In order to catch all expressions that may emerge from a try-block, multiple exception handlers (i.e., catch-blocks) may follow the try-block.

To some extent the order of the exception handlers is important. When an exception is thrown, the first exception handler matching the type of the thrown exception is used and remaining exception handlers are ignored. So only one exception handler following a try-block will be executed. Normally this is no problem: the thrown exception is of a certain type, and the correspondingly typed catch-handler will catch it. For example, if exception handlers are defined for char *s and void *s then ASCII-Z strings will be caught by the latter handler. Note that a char * can also be considered a void *, but even so, an ASCII-Z string will be handled by a char * handler, and not by a void * handler. This is true in general: handlers should be designed very type specific to catch the correspondingly typed exception. For example, int-exceptions are not caught by double-catchers, char-exceptions are not caught by int-catchers. Here is a little example illustrating that the order of the catchers is not important for types not having any hierarchical relation to each other (i.e., int is not derived from double; string is not derived from ASCII-Z):

#include <iostream>
using namespace std;

int main()
{
    while (true)
    {
        try
        {
            string s;
            cout << "Enter a,c,i,s for ascii-z, char, int, string "
                                                      "exception\n";
            getline(cin, s);
            switch (s[0])
            {
                case 'a':
                    throw "ascii-z";
                case 'c':
                    throw 'c';
                case 'i':
                    throw 12;
                case 's':
                    throw string();
            }
        }
        catch (string const &)
        {
            cout << "string caught\n";
        }
        catch (char const *)
        {
            cout << "ASCII-Z string caught\n";
        }
        catch (double)
        {
            cout << "isn't caught at all\n";
        }
        catch (int)
        {
            cout << "int caught\n";
        }
        catch (char)
        {
            cout << "char caught\n";
        }
    }
}
As an alternative to constructing different types of exception handlers for different types of exceptions, a specific class can be designed whose objects contain information about the exception. Such an approach was mentioned earlier, in section 8.3.1. Using this approach, there's only one handler required, since we know we won't throw other types of exceptions:
    try
    {
        // code throws only Exception pointers
    }
    catch (Exception *e)
    {
        e->process();
        delete e;
    }
The delete e statement in the above code indicates that the Exception object was created dynamically.

When the code of an exception handler has been processed, execution continues beyond the last exception handler directly following that try-block (assuming the handler doesn't itself use flow control statements (like return or throw) to break the default flow of execution). From this, we distinguish the following cases:

All statements in a try block appearing below an executed throw-statement will be ignored. However, destructors of objects defined locally in the try-block are called, and they are called before any exception handler's code is executed.

The actual computation or construction of an exception may be realized using various degrees of sophistication. For example, it's possible to use the operator new; to use static member functions of a class; to return a pointer to an object; or to use objects of classes derived from a class, possibly involving polymorphism.

8.5.1: The default catcher

In cases where different types of exceptions can be thrown, only a limited set of handlers may be required at a certain level of the program. Exceptions whose types belong to that limited set are processed, all other exceptions are passed on to an outer level of exception handling.

An intermediate kind of exception handling may be implemented using the default exception handler, which should (due to the hierarchical nature of exception catchers, discussed in section 8.5) be placed beyond all other, more specific exception handlers. In this case, the current level of exception handling may do some processing by default, but will then, using the the empty throw statement (see section 8.3.1), pass the thrown exception on to an outer level. Here is an example showing the use of a default exception handler:

    #include <iostream>
    using namespace std;

    int main()
    {
        try
        {
            try
            {
                throw 12.25;    // no specific handler for doubles
            }
            catch (char const *message)
            {
                cout << "Inner level: caught char const *\n";
            }
            catch (int value)
            {
                cout << "Inner level: caught int\n";
            }
            catch (...)
            {
                cout << "Inner level: generic handling of exceptions\n";
                throw;
            }
        }
        catch(double d)
        {
            cout << "Outer level still knows the double: " << d << endl;
        }
    }
    /*
        Generated output:
    Inner level: generic handling of exceptions
    Outer level still knows the double: 12.25
    */
From the generated output we may conclude that an empty throw statement throws the received exception to the next (outer) level of exception catchers, keeping the type and value of the exception: basic or generic exception handling can thus be accomplished at an inner level, specific handling, based on the type of the thrown expression, can then continue at an outer level.

8.6: Declaring exception throwers

Functions defined elsewhere may be linked to code using these functions. Such functions are normally declared in header files, either as stand alone functions or as member functions of a class.

These external functions may of course throw exceptions. Declarations of such functions may contain a function throw list or exception specification list, in which the types of the exceptions that can be thrown by the function are specified. For example, a function that could throw `char *' and `int' exceptions can be declared as

    void exceptionThrower() throw(char *, int);
If specified, a function throw list appears immediately beyond the function header (and also beyond a possible const specifier), and, noting that throw lists may be empty, it has the following generic form: throw([type1 [, type2, type3, ...]])

If a function doesn't throw exceptions an empty function throw list may be used. E.g.,

    void noExceptions() throw ();
In all cases, the function header used in the function definition must exactly match the function header that is used in the declaration, e.g., including a possible empty function throw list.

A function for which a function throw list is specified may not throw other types of exceptions. A run-time error occurs if it tries to throw other types of exceptions than those mentioned in the function throw list.

For example, consider the declarations and definitions in the following program:

    #include <iostream>
    using namespace std;

    void charPintThrower() throw(char const *, int);    // declarations

    class Thrower
    {
        public:
            void intThrower(int) const throw(int);
    };

    void Thrower::intThrower(int x) const throw(int)    // definitions
    {
        if (x)
            throw x;
    }

    void charPintThrower() throw(char const *, int)
    {
        int x;

        cerr << "Enter an int: ";
        cin >> x;

        Thrower().intThrower(x);
        throw "this text is thrown if 0 was entered";
    }

    void runTimeError() throw(int)
    {
        throw 12.5;
    }

    int main()
    {
        try
        {
             charPintThrower();
        }
        catch (char const *message)
        {
            cerr << "Text exception: " << message << endl;
        }
        catch (int value)
        {
            cerr << "Int exception: " << value << endl;
        }
        try
        {
            cerr << "Up to the run-time error\n";
            runTimeError();
        }
        catch(...)
        {
            cerr << "not reached\n";
        }
    }
In the function charPintThrower() the throw statement clearly throws a char const *. However, since intThrower() may throw an int exception, the function throw list of charPintThrower() must also contain int.

If the function throw list is not used, the function may either throw exceptions (of any kind) or not throw exceptions at all. Without a function throw list the responsibility of providing the correct handlers is in the hands of the program's designer.

8.7: Iostreams and exceptions

The C++ I/O library was used well before exceptions were available in C++. Hence, normally the classes of the iostream library do not throw exceptions. However, it is possible to modify that behavior using the ios::exceptions() member function. This function has two overloaded versions: In the context of the I/O library, exceptions are objects of the class ios::failure, derived from ios::exception. A failure object can be constructed with a string const &message, which can be retrieved using the virtual char const *what() const member.

Exceptions should be used for exceptional situations. Therefore, we think it is questionable to have stream objects throw exceptions for rather standard situations like EOF. Using exceptions to handle input errors might be defensible, for example when input errors should not occur and imply a corrupted file. But here we think aborting the program with an appropriate error message usually would be a more appropriate action. Here is an example showing the use of exceptions in an interactive program, expecting numbers:

    #include <iostream>
    using namespace::std;

    int main()
    {
        cin.exceptions(ios::failbit);

        while (true)
        {
            try
            {
                cout << "enter a number: ";

                int value;

                cin >> value;
                cout << "you entered " << value << endl;
            }
            catch (ios::failure const &problem)
            {
                cout << problem.what() << endl;
                cin.clear();
                string s;
                getline(cin, s);
            }
        }
    }

8.8: Exceptions in constructors and destructors

Only constructed objects are eventually destroyed. Although this may sound like a truism, there is a subtlety here. If the construction of an object fails for some reason, the object's destructor will not be called once the object goes out of scope. This could happen if an uncaught exception is generated by the constructor. If the exception is thrown after the object has allocated some memory, then its destructor (as it isn't called) won't be able to delete the allocated block of memory. A memory leak will be the result.

The following example illustrates this situation in its prototypical form. The constructor of the class Incomplete first displays a message and then throws an exception. Its destructor also displays a message:

    class Incomplete
    {
        public:
            Incomplete()
            {
                cerr << "Allocated some memory\n";
                throw 0;
            }
            ~Incomplete()
            {
                cerr << "Destroying the allocated memory\n";
            }
    };

Next, main() creates an Incomplete object inside a try block. Any exception that may be generated is subsequently caught:

    int main()
    {
        try
        {
            cerr << "Creating `Incomplete' object\n";
            Incomplete();
            cerr << "Object constructed\n";
        }
        catch(...)
        {
            cerr << "Caught exception\n";
        }
    }

When this program is run, it produces the following output:

    Creating `Incomplete' object
    Allocated some memory
    Caught exception
Thus, if Incomplete's constructor would actually have allocated some memory, the program would suffer from a memory leak. To prevent this from happening, the following countermeasures are available: Destructors have problems of their own when they generate exceptions. Exceptions leaving destructors may of course produce memory leaks, as not all allocated memory may already have been deleted when the exception is generated. Other forms of incomplete handling may be encountered. For example, a database class may store modifications of its database in memory, leaving the update of file containing the database file to its destructor. If the destructor generates an exception before the file has been updated, then there will be no update. But another, far more subtle, consequence of exceptions leaving destructors exist.

The situation we're about to discuss may be compared to a carpenter building a cupboard containing a single drawer. The cupboard is finished, and a customer, buying the cupboard, finds that the cupboard can be used as expected. Satisfied with the cupboard, the customer asks the carpenter to build another cupboard, this time containing two drawers. When the second cupboard is finished, the customer takes it home and is utterly amazed when the second cupboard completely collapses immediately after its first use.

Weird story? Consider the following program:

    int main()
    {
        try
        {
            cerr << "Creating Cupboard1\n";
            Cupboard1();
            cerr << "Beyond Cupboard1 object\n";
        }
        catch (...)
        {
            cerr << "Cupboard1 behaves as expected\n";
        }
        try
        {
            cerr << "Creating Cupboard2\n";
            Cupboard2();
            cerr << "Beyond Cupboard2 object\n";
        }
        catch (...)
        {
            cerr << "Cupboard2 behaves as expected\n";
        }
    }

When this program is run it produces the following output:

    Creating Cupboard1
    Drawer 1 used
    Cupboard1 behaves as expected
    Creating Cupboard2
    Drawer 2 used
    Drawer 1 used
    Abort
The final Abort indicating that the program has aborted, instead of displaying a message like Cupboard2 behaves as expected. Now let's have a look at the three classes involved. The class Drawer has no particular characteristics, except that its destructor throws an exception:
    class Drawer
    {
        size_t d_nr;
        public:
            Drawer(size_t nr)
            :
                d_nr(nr)
            {}
            ~Drawer()
            {
                cerr << "Drawer " << d_nr << " used\n";
                throw 0;
            }
    };

The class Cupboard1 has no special characteristics at all. It merely has a single composed Drawer object:

    class Cupboard1
    {
        Drawer left;
        public:
            Cupboard1()
            :
                left(1)
            {}
    };

The class Cupboard2 is constructed comparably, but it has two composed Drawer objects:

    class Cupboard2
    {
        Drawer left;
        Drawer right;
        public:
            Cupboard2()
            :
                left(1),
                right(2)
            {}
    };

When Cupboard1's destructor is called, Drawer's destructor is eventually called to destroy its composed object. This destructor throws an exception, which is caught beyond the program's first try block. This behavior is completely as expected. However, a problem occurs when Cupboard2's destructor is called. Of its two composed objects, the destructor of the second Drawer is called first. This destructor throws an exception, which ought to be caught beyond the program's second try block. However, although the flow of control by then has left the context of Cupboard2's destructor, that object hasn't completely been destroyed yet as the destructor of its other (left) Drawer still has to be called. Normally that would not be a big problem: once the exception leaving Cupboard2's destructor is thrown, any remaining actions would simply be ignored, albeit that (as both drawers are properly constructed objects) left's destructor would still be called. So this happens here too. However, left's destructor also throws an exception. Since we've already left the context of the second try block, the programmed flow control is completely mixed up, and the program has no other option but to abort. It does so by calling terminate(), which in turn calls abort(). Here we have our collapsing cupboard having two drawers, even though the cupboard having one drawer behaves perfectly.

The program aborts since there are multiple composed objects whose destructors throw exceptions leaving the destructors. In this situation one of the composed objects would throw an exception by the time the program's flow control has already left its proper context. This causes the program to abort.

This situation can be prevented if we ensure that exceptions never leave destructors. In the cupboard example, Drawer's destructor throws an exception leaving the destructor. This should not happen: the exception should be caught by Drawer's destructor itself. Exceptions should never be thrown out of destructors, as we might not be able to catch, at an outer level, exceptions generated by destructors. As long as we view destructors as service members performing tasks that are directly related to the object being destroyed, rather than a member on which we can base any flow control, this should not be a serious limitation. Here is the skeleton of a destructor whose code might throw exceptions:

    Class::~Class()
    {
        try
        {
            maybe_throw_exceptions();
        }
        catch (...)
        {}
    }

8.9: Function try blocks

Exceptions might be generated while a constructor is initializing its members. How can exceptions generated in such situations be caught by the constructor itself, rather than outside of the constructor? The intuitive solution, nesting the object construction in a nested try block does not solve the problem (as the exception by then has left the constructor) and is not a very elegant approach by itself, because of the resulting additional (and somewhat artificial) nesting level.

Using a nested try block is illustrated by the next example, where main() defines an object of class DataBase. Assuming that DataBase's constructor may throw an exception, there is no way we can catch the exception in an `outer block' (i.e., in the code calling main()), as we don't have an outer block in this situation. Consequently, we must resort to less elegant solutions like the following:

    int main(int argc, char **argv)
    {
        try
        {
            DataBase db(argc, argv);    // may throw exceptions
            ...                         // main()'s other code
        }
        catch(...)                      // and/or other handlers
        {
            ...
        }
    }
This approach may potentially produce very complex code. If multiple objects are defined, or if multiple sources of exceptions are identifiable within the try block, we either get a complex series of exception handlers, or we have to use multiple nested try blocks, each using its own set of catch-handlers.

None of these approaches, however, solves the basic problem: how can exceptions generated in a local context be caught before the local context has disappeared?

A function's local context remains accessible when its body is defined as a function try block. A function try block consists of a try block and its associated handlers, defining the function's body. When a function try block is used, the function itself may catch any exception its code may generate, even if these exceptions are generated in member initializer lists of constructors.

The following example shows how a function try block might have been deployed in the above main() function. Note how the try block and its handler now replace the plain function body:

    int main(int argc, char **argv)
    try
    {
        DataBase db(argc, argv);    // may throw exceptions
        ...                         // main()'s other code
    }
    catch(...)                      // and/or other handlers
    {
        ...
    }
Of course, this still does not enable us have exceptions thrown by DataBase's constructor itself caught locally by DataBase's constructor. Function try blocks, however, may also be used when implementing constructors. In that case, exceptions thrown by base class initializers (cf. chapter 13) or member initializers may also be caught by the constructor's exception handlers. So let's try to implement this approach.

The following example shows a function try block being used by a constructor. Note that the grammar requires us to put the try keyword even before the member initializer list's colon:

    #include <iostream>

    class Throw
    {
        public:
            Throw(int value)
            try
            {
                throw value;
            }
            catch(...)
            {
                std::cout << "Throw's exception handled locally by Throw()\n";
                throw;
            }
    };

    class Composer
    {
        Throw d_t;
        public:
            Composer()
            try             // NOTE: try precedes initializer list
            :
                d_t(5)
            {}
            catch(...)
            {
                std::cout << "Composer() caught exception as well\n";
            }
    };

    int main()
    {
        Composer c;
    }
In this example, the exception thrown by the Throw object is first caught by the object itself. Then it is rethrown. As the Composer's constructor uses a function try block, Throw's rethrown exception is also caught by Composer's exception handler, even though the exception was generated inside its member initializer list.

However, when running this example, we're in for a nasty surprise: the program runs and then breaks with an abort exception. Here is the output it produces, the last two lines being added by the system's final catch-all handler, catching all exceptions that otherwise remain uncaught:

    Throw's exception handled locally by Throw()
    Composer() caught exception as well
    terminate called after throwing an instance of 'int'
    Abort
The reason for this is actually stated in the C++ standard: at the end of a catch-handler implemented as part of a destructor's or constructor's function try block, the original exception is automatically rethrown. The exception is not rethrown if the handler itself throws another exception, and it is not retrown by catch-handlers that are part of try blocks of other functions. Only constructors and destructors are affected. Consequently, to repair the above program another, outer, exception handler is still required. A simple repair (applicable to all programs except those having global objects whose constructors or destructors use function try blocks) is to provide main with a function try block. In the above example this would boil down to:
    int main()
    try
    {
        Composer c;
    }
    catch (...)
    {}
Now the program runs as planned, producing the following output:
    Throw's exception handled locally by Throw()
    Composer() caught exception as well

A final note: if a constructor or function using a function try block also declares the exception types it may throw, then the function try block must follow the function's exception specification list.

8.10: Standard Exceptions

All data types may be thrown as exceptions. However, the standard exceptions are derived from the class exception. Class derivation is covered in chapter 13, but the concepts that lie behind inheritance are not required for the the current section.

All standard exceptions (and all user-defined classes derived from the class std::exception) offer the member

    char const *what() const;
describing in a short textual message the nature of the exception.

Four classes derived from std::exception are offered by the language: