A ti(catch) clause consists of the keyword tt(catch) followed by a parameter
list defining one parameter specifying type and (parameter) name of the
exception caught by that particular tt(catch) handler. This name may then be
used as a variable in the compound statement following the tt(catch) clause.
Example:
        verb(    catch (string &message)
    {
        // code to handle the message
    })

Primitive types and objects may be thrown as exceptions. It's a bad idea
to throw a pointer or reference to a local object, but a pointer to a
em(dynamically) allocated object may be thrown if the exception handler
deletes the allocated memory to prevent a i(memory leak). Nevertheless,
throwing such a pointer is dangerous as the exception handler won't be able to
distinguish dynamically allocated memory from non-dynamically allocated
memory, as illustrated by the next example:
        verb(    try
    {
        static int x;
        int *xp = &x;

        if (condition1)
            throw xp;

        xp = new int(0);
        if (condition2)
            throw xp;
    }
    catch (int *ptr)
    {
        // delete ptr or not?
    })

Close attention should be paid to the nature of the parameter of the
exception handler, to make sure that when pointers to dynamically allocated
memory are thrown the memory is returned  once the handler has processed
the pointer. In general pointers should not be thrown as exceptions. If
dynamically allocated memory must be passed to an exception handler then the
pointer should be wrapped in a smart pointer, like tt(unique_ptr) or
tt(shared_ptr) (cf. sections ref(UNIQUEPTR) and ref(SHAREDPTR)).

    Multiple tt(catch) handlers may follow a tt(try) block, each handler
defining its own exception type.  The em(order) hi(exception handler: 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. Eventually at most one exception
handler following a tt(try)-block is activated. Normally this is of no
concern as each exception has its own unique type.

    Example: if exception handlers are defined for tt(char *)s and ti(void *)s
then NTBSs are caught by the former handler. Note that a tt(char
*) can also be considered a tt(void *), but the exception type matching
procedure is smart enough to use the tt(char *) handler with the thrown
NTBS. Handlers should be designed very type specific to catch the
correspondingly typed exception. For example, tt(int)-exceptions are not
caught by tt(double)-catchers, tt(char)-exceptions are not caught by
tt(int)-catchers. Here is a little example illustrating that the order of the
catchers is not important for types not having any hierarchal relationship to
each other (i.e., tt(int) is not derived from tt(double); tt(string) is not
derived from an NTBS):
        verbinclude(-a examples/catchers.cc)
    Rather than defining specific exception handlers a specific class can be
designed whose objects contain information about the exception. Such an
approach was mentioned earlier, in section ref(EMPTYTHROW). Using this
approach, there's only one handler required, since we em(know) we don't throw
other types of exceptions:
        verb(    try
    {
        // code throws only Exception objects
    }
    catch (Exception &ex)
    {
        ex.handle();
    })

When the code of an exception handler has been processed, execution continues
beyond the last exception handler directly following the matching
tt(try)-block (assuming the handler doesn't itself use flow control statements
(like tt(return) or tt(throw)) to break the default flow of execution). The
following cases can be distinguished:
    itemization(
    it() If em(no) exception was thrown within the tt(try)-block no exception
handler is activated, and execution continues from the last statement in
the tt(try)-block to the first statement beyond the last tt(catch)-block.
    it() If an exception em(was) thrown within the tt(try)-block but neither
the current level nor another level contains an appropriate exception handler,
the program's default exception handler is called, aborting the program.
    it() If an exception was thrown from the tt(try)-block and an appropriate
exception handler is available, then the code of that exception handler is
executed. Following that, the program's execution continues at the first
statement beyond the last tt(catch)-block.
    )
    All statements in a tt(try) block following an executed
tt(throw)-statement are ignored. However, objects that were successfully
constructed within the tt(try) block before executing the tt(throw) statement
em(are) destroyed before any exception handler's code is executed.
