advertisement

Print
C++ Pocket Reference

Programming with Exceptions in C++

by Kyle Loudon, author of C++ Pocket Reference
05/05/2003

Editor's note: O'Reilly author Kyle Loudon has selected the following excerpt on "Exception Handling in C++", from his upcoming C++ Pocket Reference, for publication on O'Reilly Network. He starts things off with a brief introduction to the topic, then concludes with a new section he's added on the key differences between exception handling in C++ and Java.

Introduction

Wouldn't it be great if nothing unexpected ever occurred during the execution of a program? Unfortunately, in reality, a sizable part of almost any piece of software is devoted to recognizing all of the things that could go wrong, and more importantly, how to handle them.

Exception handling is one particularly effective approach to dealing with unexpected, or exceptional, conditions. Without exception handling, dealing with exceptional conditions often requires complicated, multi-way conditionals that are heavily nested and awkward. Exception handling offers a natural way to reduce such intricate and error-prone sections of code.

When C++ was officially standardized in 1998, the standard defined several facilities related to exception handling. These are outlined in the following excerpt from the C++ Pocket Reference. For software developers with Java experience, some key differences between exception handling in C++ and Java are listed at the end of the excerpted section.

Exception Handling in C++

Exception handling is performed using try and catch blocks. For example:

try
{
   // Watch out for a bad file name
   // or no file handles available.
}
catch (BadFileName &e)
{
   // Handle BadFileName exceptions.
}
catch (HandlesGone &e)
{
   // Handle HandlesGone exceptions.
}

try

Related Reading

C++ Pocket Reference
By Kyle Loudon

A try block delineates a context in which exceptions may be raised, or thrown. When an exception is thrown within a try block, execution immediately jumps to the start of a catch block responsible for dealing with the exception, if such a block exists.

throw

You throw an exception inside of a try block using the throw operator. For example:

throw e;

The type of the exception is used to determine which catch block to execute. The exception is passed as an argument to the catch block so that it can be used in handling the exception. Within a catch block, you can re-throw an exception using throw with no operand. The following rules also apply:

  • Exceptions can be of intrinsic types or classes that you define yourself. Exception classes do not have to be derived from any particular class.

  • Some standard exceptions are defined for use by the language (e.g., bad_cast, thrown by the dynamic_cast operator) and facilities in the C++ Standard Library.

  • Standard exceptions are all derived from the exception class, which is defined in the standard header file <exception>. The what member function of exception gets a standard exception's name.

catch

One or more catch blocks follow a try block to define how specific types of exceptions should be handled. catch blocks are tried in the order in which they appear. The first catch block found to match the exception's type or its base class is passed the exception to handle. Therefore, if you catch exceptions of both a derived class and its base class, the catch block for the derived class needs to appear first.

Note: Exceptions are often declared as references in catch blocks so that polymorphic behavior is possible when accessing the object to handle the exception.

An ellipsis (...) can be used to indicate that any type should be caught. For example:

try
{
   // Watch out for a bad file name.
}
catch (BadFileName &e)
{
   // Handle BadFileName exceptions.
}
catch (...)
{
   // Handle exceptions not covered.
}

If no catch block is suitable, the stack is unwound to determine if a suitable catch block appears earlier in the calling chain. If the stack unwinds completely without finding a suitable catch block, the standard function terminate is called. The default behavior for this function is to terminate the program. You can install your own handler that terminates exception processing by calling set_terminate (include <exception>) This function takes a pointer to a handler function with the signature below:

void terminate_handler_function();

set_terminate returns the previously installed handler. The terminate handler you provide should take any actions necessary for unhandled exceptions, then terminate execution of the program.

Exception Specifications

An exception specification is a guarantee to the caller of a function that only certain exceptions will be thrown within it. For example:

void fetch(char *name, char *&data)
   throw (BadFileName, HandlesGone);

If the function throws an exception of a type not listed in the exception specification, or of a type not derived from one of the listed types, the standard function unexpected is called. The default behavior for this function is to terminate the program. You can install your own handler for this by calling set_unexpected (include <exception>). This function takes a pointer to a handler function with the signature below:

void unexpected_handler_function();

set_unexpected returns the previously installed handler. The handler you provide should take any actions necessary for unexpected exceptions, then terminate execution of the program. It can also throw exceptions of its own.

The following rules also apply to exception specifications:

  • An empty set of parentheses specifies that a function throws no exceptions.

  • If you omit the exception specification altogether, there is no limit on the types or number of exceptions that can be thrown.

  • A definition for a function must list the same exceptions as in its declaration.

  • If a virtual member function has an exception specification, all member functions of derived classes that override the function must have the same exception specification.

Exception Handling in Java

Java programmers should note that despite some seemingly apparent similarities, exception handling in C++ differs from Java's exception handling, primarily in the following, sometimes subtle, ways:

  • In Java, all exceptions are ultimately derived from the class Throwable. In C++, exceptions can be of any type. However, standard exceptions (e.g., those thrown by the language and facilities in the standard library) are all derived from the class exception.

  • Java has checked and unchecked exceptions. In C++, this distinction does not exist.

  • In Java, methods must use throws to specify exceptions that are thrown (either directly or indirectly) and not caught within the method; a check for this is performed during compilation. In C++, if an exception specification is provided for a member function and the function throws and does not catch an exception that is not in the function's exception specification, the omission is addressed at runtime (see the description of the standard function unexpected in the excerpt).

  • In addition to catch blocks, Java allows a finally block to be defined. finally does not exist in C++.

  • In Java, an ellipsis (...) cannot be used in place of an exception specified with catch. In C++, this syntax is used to catch all exceptions not caught by other catch blocks.

Kyle Loudon is a software developer at Yahoo! where he leads a group doing user interface development. Some of Kyle's experiences prior to joining Yahoo! include working on the user interface for the original Apple iPod, writing software for various other mobile devices, and leading the user interface group at Jeppesen Dataplan (a Boeing company) in the development of a flight planning system used by airlines around the world.


O'Reilly & Associates will soon release (May 2003) C++ Pocket Reference.


Return to the O'Reilly Network.