|
Programming with Exceptions in C++by Kyle Loudon, author of C++ Pocket Reference05/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.
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 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
|
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.
throwYou 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.
catchOne 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.
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.
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 engineer at Jeppesen Dataplan in Los Gatos, California, where he leads the graphical interface development group in developing flight planning software used by commercial airlines, corporate flight departments, and other facets of general aviation.
O'Reilly & Associates will soon release (May 2003) C++ Pocket Reference.
A Beta Sample Excerpt, "Statements," is available free online.
You can also look at the full description of the book.
For more information, or to order the book, click here.
Return to the O'Reilly Network.
Copyright © 2007 O'Reilly Media, Inc.