- The Error Problem
- Exceptions
- Exception Basics
- Exception Problems
- Basic Exception Mechanisms
- The
throw Statement
- The
catch Statement
- The
try Statement
- Exception Problems II
- Exception Mechanism Refinements
- Exception Problems III
- Further Exception Refinements
- Points to Remember
- What happens if there's an error in a constructor?
box b(1, 2); // How can box::box() handle internal errors?
- What happens if there's an error in an overloaded operator?
b1 = b1 + b2; // how can box::operator + () handle internal errors?
- The code can ignore the error.
- Not always possible or advisable.
- The code can print an error message and die.
- Helpful, but not always useful.
- The code can try to handle the error.
- Possible, but difficult because the context isn't known.
- The code can indicate an error some how.
- This is the error pass-along problem.
- out-of-band errors - exceptions
- not propagated along parameters, return values, or globals -
constructors and operators
- can be ignored by intermediate code - pass-along
- the call stack
- the top of the call stack can throw an exception
- a procedure in the call stack can catch an exception
- the procedure closest to the top wanting the exception gets it
- the intervening processes are unwound - the catching process is the new
call-stack top
- the throwing and intervening processes are terminated immediately
- intervening processes have no chance to clean up
- coordinated exceptions among independent modules requires work
- The
throw
statement lauches (throws) an exception.
-
throw
expr throws the value expr as an exception.
- like
return
in syntax and semantics
- expr can be a value of any type
-
catch (
type-spec [ name ] ) {
body
}
- catches a thrown exception
- with no name, the actual exception is unknown
- exception types must match exactly - with no conversions but with
polymorphism
- the ellipsis
catch(. . .) { }
catches any exception
- when caught, the body is executed with name (if defined) as
a local variable.
-
try {
body }
catch-stmt . . .
- execute the code in body - fall off the end with no exception
- jump from body to the catch-stmts on exception - a normal
scope exit; destructors are called
- search for a matching catch-stmt in order
- an exception is considered handled as soon as a match is found
- after executing the associated
catch
body, continue after
the try
- if no catch-stmt matches, terminate the current procedure and
continue up the stack
- the scope of the
try
is not the scope of a catch
- exception refinements - it gets confusing
- an exception not handled by
main()
causes termination
- an exception thrown in a
catch
body is like any other
exception
- exceptions raised in destructors cause immediate termination - no stack
unwinding
- exception class values
-
<exception>
defines the virtual class exception
- defines
char * exception::what(void) const
-
<stdexcept>
defines some derived exceptions -
runtime_error
and logic_error
- a
catch
handler can rethrow an exception using throw
- a procedure can list the exceptions it throws with a
throw
clause
-
throw (
ex1, ex2, . . . )
- follows the procedure's formal parameter list
- only the listed exceptions can be thrown from the procedure - other
exceptions cause termination
- by default a procedure can throw all exceptions
- throw clauses are useful but dangerous - must list all possible
exceptions; unlisted exceptions get turned into
unexpected
exceptions
- c++ throws several exceptions -
bad_alloc
in new
in
particular
- there's also a non-throwing
new
- this used to be standard
-
auto_pointers
provide a means for automatic resource recovery on
exceptions
- Don't use them - nasty, asynchronous, implicit control flow.
- If you do use them,
- Make sure they indicate exceptional conditions - don't use them to
exit a loop or return from a procedure; lisp programmers beware
- Keep it as simple as possible - short throw-catch relations and
simple values returned
This page last modified on 8 February 2003.