C++ Exceptions
What should a program do when something goes wrong? When designing software, the first question usually is �What does the program do?� The customer is asked about what goes in and what comes out of a program, but not if they intend to enter letters into a field reserved for numbers. Of course, it isn�t always obvious how a program might fail -- but the goal of any professional developer should be to ensure that when things do �go wrong�, the program handles the situation effectively, with grace. Error handling is a fundamental component of software engineering, and we need to consider carefully how our programs handle adversity.
�Exception handling� means different things to different people, which may explain why C-style error handling comes in so many incompatible flavors:
- Some functions return a special value to indicate a problem, such as malloc�s return of NULL to indicate a memory allocation failure. This technique requires the caller to check the return value, something many rushed or careless coders simply don�t do.
- When something goes wrong, a program can set the value of a global error variable. If you�ve worked with C for any time, you�ll have encountered errno, the common error variable that can be set by several standard library functions. Like all global values, errno can be changed in many places, usually in routines outside your program�s direct control. You may not know which library functions call each other, and checking errno often can be very inefficient.
- Callback functions provide a somewhat better solution; the general technique is to set a function argument or a global pointer to the address of an error-handling function to be called when trouble arises. If the pointer is a global variable, you have to wonder what other parts of the program might be using (and changing) it. Passing the function address as a call argument adds overhead to your program.
- The program can simply stop on errors -- an unacceptable form of error-handling for anything but the most basic command-line applications.
- C was originally designed as a system-level programming language, and, as such, it implements the concept of signals for handling asynchronous operating system events. Standard C (and C++) define a small set of signals that indicate various errors (e.g., division by zero) or program interrupts (e.g., pressing Ctrl-C). Most compilers implement additional signals, some of which are not error-related; for example, UNIX uses signals to announce communications events.
Consistency is vital in these days of million-line programs, written by dozens of programmers. C-style programs closely tie error-handling code to the function that reports the problem; a programmer is required to be especially diligent in checking every potential instance of error. By mixing its error metaphors, C makes a programmer work hard to develop reliable software. Handling errors must be universal, simple, and consistent -- which is something C++ provides with its exception-handling mechanism.
Exception Handlers
An exception represents an unexpected event during a program�s execution -- i.e., a memory allocation error, the inability to open a file, or division by zero. In C++, a throw expression generates an exception based on an object; that object can then be trapped by an exception handler. This example shows a basic implementation of exception handling.
// exception classes
class BlewUp { };
class Kaboom { };
void HardWork()
{
// trap exceptions in this try-block
try
{
if (something_wrong())
throw BlewUp(); // generate an exception
if (uhoh())
throw Kaboom(); // generate an exception
do_whatever();
}
// exception handlers
catch (BlewUp)
{
// handle a BlewUp exception
}
catch (Kaboom)
{
// handle a Kaboom exception
}
catch (...)
{
// handle any other exceptions
}
// here�s where we come if there isn�t an exception
cout << �outa here� << endl;
}
The code fragment begins by declaring two classes that represent exceptions. The try block defines an area of code that handles exceptions; each catch block describes how to handle an exception of a specific type. The try and catch keywords go together; you can't have try without at least one catch, and catch blocks cannot exist without a preceding try block.
A throw statement initiates the exception process, specifying an object that represents the exception. Upon executing a throw, the program looks back through its execution history until it finds a try block. The type of the exception object is matched against the types defined by catch blocks; for example, throw Kaboom() causes program execution to jump into the catch (Kaboom) code block.
You define a �catch all� handler with catch (...), which handles any exception not processed by other exception handlers. If you don't define a catch (...) block, unhandled exceptions result in calls to the currently-defined terminate� function. I'll talk about terminate() later in this document; for now, let�s look at what happens when we do provide handlers for our exceptions.
If a try block does not generate an exception, program execution continues with the statement immediately following the block's associated list of catch blocks. Also, if a catch block does not transfer control elsewhere, program execution continues immediately after the last catch block. So in the example above, the stream output �outa here� is always executed, unless the try-catch statement explicitly bypasses it with a return or program exit.
Each try and catch block defines a separate scope. A catch block cannot access objects declared within its try block or in other catch blocks. You cannot use a goto statement to enter a catch block, or to skip from one catch block to another, or to return to some point in the try block. However, a goto can jump completely out of a catch or try block:
void BusyWork()
{
try
{
// do something
}
catch (Hell h)
{
if (!h.HasSnowball())
{
cout << "A cold day in hell!\n";
abort();
}
}
}
If a function is called from within a try block, any exceptions it throws are caught by the try block's exception handlers:
class Problem {};
void Level1
{
try
{
Level2();
}
catch (Problem)
{
// do something with a Problem
}
}
void Level2()
{
Level3();
if (SomethingBad())
throw Problem;
}
void Level3()
{
if (WentWrong())
throw Problem;
}
Stack Unwinding
A program tracks try-catch blocks in a stack-like fashion. The execution of a throw statement �pops� try-catch blocks from the exception handler stack, until one of two things happens: a handler is found for the type of exception thrown, or the stack is empty. In the first case, the handler is executed; in the second case, the program calls the current terminate function.
You can think of every function as having an implicit try-catch block. In the next example, the comments describe the implicit try-catch block that wraps all other statements in the function NoTryCatch. In other words, if a throw statement is not inside a local try-catch block, it immediately terminates the current function and looks for an exception handler in the calling function.
// function without an explicit try handler
void NoTryCatch()
{
// try
// {
vector<int> ivec;
cout << �Hi there!� << endl;
// }
// catch(...)
// {
// throw the execption to whoever called NoTryCatch
// }
}
The act of �popping� handlers off the stack is called stack unwinding. As a throw statement moves back up the chain of handlers, looking for an appropriate exception handler, the program �unwinds� the call chain, destroying objects created in higher-level functions and freeing stack space. This figure shows how exceptions are handled in a series of nested functions.

That program displays:
handled Except1 in TestExLevel3 (inner) handled Except2 in TestExLevel2 handled Except1 in TestExLevel1
When the program enters TestLevelEx4, it has an exception stack that looks like this:
TestExLevel3, catch(Except1) inner try block TextExLevel3, catch(Except1) outer try block TestExLevel2, catch(Except2) TestExLevel1, catch(Except1), catch(�) terminate()
The exception handler stack does not necessarily correspond to the call stack, since try-catch blocks may be nested within functions. After TestExLevel4 throws, program execution jumps to the inner exception handler defined in TextExLevel3; a message is displayed. After the message is displayed, execution continues with the exception stack looking like this:
TextExLevel3, catch(Except1) outer try block TestExLevel2, catch(Except2) TestExLevel1, catch(Except1), catch(�) terminate()
While the throw Except2 statement is within the outer try-catch block of TestLevel3, that block does not define a handler for Except2 objects -- and so program execution �pops� the current exception handler, exits TestLevel3, and looks to the try-catch block defined in TestExLevel2. There the program finds and executes the handler for an Except2 object, and the exception stack is now:
TestExLevel1, catch(Except1), catch(�) terminate()
When TestExLevel2 throws the Except1, the stack further unwinds into TestExLevel1�s try-catch block. Once that handler is finished, the exception stack contains a single entry:
terminate()
The last statement in TestExLevel1 is another throw--and the program invokes the terminate function, since that is the only item left on the exception stack.
Unwinding exits functions and destroys objects automatically. In terms of automatic objects, a throw acts like a return, calling destructors for any objects created previously within the function. Here's an example of an automatic object being destroyed by an exception:
class DataRecord
{
public:
DataRecord();
~DataRecord();
// assume a complex class definition
};
// exception class
class Trouble { };
void StartHere()
{
try
{
WorkHere();
}
catch (Trouble)
{
// handle Trouble
}
}
void WorkHere()
{
DataRecord dRec;
DataRecord * pRec = new DataRecord;
if (some_problem)
throw Trouble;
}
If the throw Trouble statement is executed in WorkHere, the program calls the DataRecord destructor for dRec. However, it won't automatically call a destructor for pRec, since pRec is a dynamic object. Use classes to force the destruction of dynamically-allocated objects. If you want to ensure the automatic destruction of pRec above, you could rewrite it like this:
class DataRecord
{
public:
DataRecord();
~DataRecord();
// assume a complex class definition
};
// define a pointer to a DataRecord
class DataRecPtr
{
public:
DataRecord * ptr;
private:
DataRecPtr()
{ ptr = new DataRecPtr; }
~DataRecPtr();
{ delete ptr; }
operator DataRecord * ()
{ return ptr; }
};
DataRecPtr::DataRecPtr()
{
ptr = new DataRecord;
if (ptr == NULL)
throw xalloc("DataRecPtr not allocated",n);
}
// exception classes
class Trouble { };
void StartHere()
{
try
{
WorkHere();
}
catch (Trouble)
{
// do something about Trouble
}
}
void WorkHere()
{
DataRecord dRec;
DataRecPtr pRec;
pRec =
if (some_problem)
throw Trouble;
}
Now that pRec is an object, any exit from the WorkHere function -- including a thrown exception -- automatically deletes (and subsequently destroys) pRec's dynamic DataRecord object.
Using objects to control resource allocation is essential to building solid, reliable C++ programs. By encapsulating resource allocations (be they requests for dynamic memory or the use of a file) you guarantee that those resources are properly handled on function exit or program termination. It's easy to forget to explicitly close files or delete dynamic objects, and the chance of overlooking something increases as a program becomes more complex. Objects can make your life easier by making your program remember things for you.
The terminate Function
If you haven't defined a catch (...) block, and a type-specific exception handler can't be found, the exception is handled by a global function named terminate. By default, terminate is implemented as a call to the standard library function abort. A program also calls terminate if an exception is thrown and no enclosing try block is found.
Simple termination is too severe a step in many situations; before a program terminates, you may want to write files or release system resources. The set_terminate function sets the function called in place of the default terminate:
#include <except>
void MyTerminate()
{
// clean-up program
abort();
}
int main()
{
oldterm = set_terminate(My_Terminate);
// do program stuff
// restore old handler
set_terminate(oldterm);
return 0;
}
The Standard C++ header file exception contains a prototype for set_terminate and a definition for the terminate_function type:
typedef void (* terminate_function)(); terminate_function set_terminate(terminate_function);
Some compilers limit the actions that can be performed inside a terminate function, so check your compiler documentation for specifics. In portable code, it is best to keep terminate as simple as possible, to avoid enoucntering any compiler-imposed limitations.
Templates and Exceptions
Exceptions defined within a template class can be specific to each generated class.
template <class T> class List
{
public:
class EmptyList { }; // exception class
// ...
};
Then, a catch block would need to specify the type of List that it is handling:
catch (List<int>::EmptyList)
{
// do something
}
You need to define a handler for each expected type of List; those List types not specified have their exceptions handled by the terminate function. Or, you can define an EmptyList exception outside the List class, making it global to all list types.
class EmptyList { }; // exception class
template <class T> class List
{
public:
// ...
};
Exceptions defined within a class follow the standard access rules. If a class only handles an exception internally, the exception class should be declared private or protected. If you want the exception to be handled externally, make it public or define it outside of the error-producing class.
Rethrowing an Exception
You can cascade the handling of exceptions by having a lower level catch block rethrow an exception to a higher level. A throw statement without an argument rethrows the last exception to the next highest level exception handler. If no previous exception exists, the program calls terminate.
catch (ErrorRange er)
{
cout << "Array index bad: " << er.index << endl;
throw;
}
Upon entry to a handler, an exception is considered to have been handled. If a handler rethrows its exception, the previous handler is invoked, thus preventing an endless loop. If the higher level doesn't have a handler, the program calls terminate. To convert one exception type to another, use code like this:
catch (ThisException)
{
throw ThatException;
}
Using class hierarchies allows you organize and group related exceptions. Catch a base class type, and you also catch any exceptions thrown with its subclasses. A set of exception objects for memory allocation problems could be derived from a base MemoryException class: OutOfMemory, ZeroAlloc, etc. A single catch (MemoryException) handler would catch all memory exceptions. Using this technique makes code more robust and prevents the need for having a catch block for every possible exception in a family.
Constructors and Destructors
When a constructor fails, throw an exception. It�s a simple as that. You can�t return anything from a constructor anyway, so there�s really no practical alternative to using an exception.
An object is considered complete when its constructor successfully returns. If you throw an exception inside of a constructor, the compiler will not perform any clean-up on the incomplete object itself. Any automatic objects in the constructor is destroyed -- but members of the object itself may be left in an indeterminate state. This makes sense, since the compiler has no way of telling a destructor how to destroy an incomplete object. Be sure your exceptions "understand" an incomplete object�s state, and clean up any members as appropriate.
Additional consideration must also be applied to throwing exceptions from destructors. Standard C++ states that a program immediately terminates if any exception is thrown during stack unwinding. This makes sense; Standard C++ intended exceptions to represent serious program errors, and having a �serious� problem while processing another is a good indication that something very bad has happened in your code.
To avoid the �exceptions during exceptions� problem, use the Standard C++ function unhandled_exception, which is defined in the header file exception. It returns true while stack unwinding is occurring for an exception. Here's how to use unhandled_exception to protect your destructors against �exception exceptions�.
#include <exception>
Object::~Object()
{
if (!unhandled_exception())
{
// throw any exceptions you need to!
}
}
Exception Objects
An exception is identified by a data type. You could, for example, have an exception like this:
try
{
// do something
throw 1;
}
catch (int i)
{
// handle an int error
}
However, you couldn't say:
throw int;
An exception is an object, not a type. To access the data in a thrown object, and catch block can provide an identifier for that object:
catch (int i)
{
cout << "int exception " << i << endl;
}
A catch block can specify an argument of type T, references to T, and const versions of either. It cannot specify default arguments, though, since a catch block is only called for an existing object. One option is to use an enumerated type to identify exceptions:
enum Problem { BadInput, LowMemory, StupidUser };
void SomeFunk()
{
try
{
// code that throws exceptions
throw Problem(StupidUser);
}
catch (Problem p)
{
switch (p)
{
case BadInput:
break;
case LowMemory:
break;
case StupidUser:
break;
}
}
}
Keep in mind that a typedef merely creates an alias for an existing type. For example:
typedef int ExInt; ExInt ei = 1; throw ei;
The above throw statement would look for a catch (int) block. The compiler should reject any attempt to create both catch (int) and catch (ExInt) blocks in the same try/catch statement, since ExInt is merely another name for int.
Always define your exception types with classes. Simple types like int can only pass simple information; an exception class can provide clear information on the problem and its causes.
Exception Specifications
A function declaration may include a throw specification. For example,
void Boing() throw (Stuck, OutOfBounds)
{
// do whatever boing does
}
is roughly equivalent to
void Boing()
{
try
{
// do whatever Boing does
}
catch (Stuck)
{
throw;
}
catch (OutOfBounds)
{
throw;
}
catch (...)
{
unexpected();
}
}
Without a throw specification, the compiler assumes that a function can throw any exception. Conversely, using a throw() specification (with an empty list in parenthesiss) states that a function does not throw any exceptions. This is known as a "nothrow" specification, and allows a compiler to assume that it does not need to account for exceptions when compiling code that uses a function declared in this manner.
If a function throws an exception that is not in that function's throw declaration, the unexpected function is called. For example,
void DoStuff() throw(bad_alloc,Crash)
{
// stuff to do
}
states that it only throws bad_alloc and Crash exceptions. Should an exception of another type -- say, bad_type -- be thrown within DoStuff, the unexpected function is invoked. If unexpected, in turn, throws an exception not listed in DoStuff�s specification (either bad_alloc or Crash), a bad_exception is thrown in its stead.
class bad_exception : public exception
{
public:
// constructor
bad_exception() throw();
// copy constructor
bad_exception (const bad_exception & ba) throw();
// assignment
bad_exception & operator = (const bad_exception & ba) throw();
// destructor
virtual ~bad_exception() throw();
// reporting
virtual const char * what() const throw();
};
By default, unexpected calls terminate, which in turn calls abort. The set_unexpected function defines the handling of unexpected exceptions:
void MyUnexpected()
{
// clean-up program
abort();
}
int main()
{
oldunexp = set_unexpected(MyUnexpected);
// do program stuff
// restore old handler
set_unexpected(oldunexp);
return 0;
}
The header file except defines the unexpected_function type and the set_unexpected function:
typedef void (* unexpected_function)(); unexpected_function set_unexpected(unexpected_function);
A few more points to consider:
- Unexpected exceptions don't pass beyond the calling function.
- A catch (...) handler won't trap unexpected exceptions from functions with throw specifications.
- Many compiler will not "inline" a function containing a throw specification.
- Some compilers, like Microsoft's Visual C++ 12.0 (Visual Studio 6), ignore throw specifications entirely.
- You may not want a program to terminate abruptly on unexpected exceptions, and redefining the unexpected function may not work for every program design.
- Underlying library functions and classes could throw exceptions you don't expect.
- Template functions can not use exception specifications, given the inability to know which exceptions will be thrown by the instantiating type(s).
Exception specifications are one of the least-used features in Standard C++ -- for several good reasons. I don�t use throw declarations on my functions, preferring instead to implement try-catch blocks that gracefully handle any errors. However, you may use a library that uses these declarations, so you need to know their intend purpose.
A special case is the nothrow specification, throw(). Use this on functions that you know do not throw exceptions, such as functions where you handle all possible exceptions in an internal try-catch block. This provides a clear message to the user and compiler that a function doesn't throw exceptions -- and clear messages mean clean designs and reliable code.
Non-Fatal Exceptions
You can use an exception to handle an non-error condition -- that doesn't mean doing so is a good idea. This code uses an exception to trap a lookup failure in a table:
class Info {};
class TextTable
{
public:
Info Lookup(char * key);
class LookupFailure { };
};
Info TextTable::Lookup(char * key)
{
// if key is not found
throw(TextTable::LookupFailure);
}
void FindIt(TextTable & table, char * key)
{
try
{
Info data = table.Lookup(key);
}
catch (LookupFailure)
{
// handle lack of information
}
}
While exceptions are a powerful tool, using them to control non-error conditions can lead to sloppy programming. As I mentioned earlier in this chapter: Exceptions provide a structured mechanism for handling unusual program conditions or errors. Straying too far from that philosophy undermines the concept of layering and organizing your program's code. While you can use exceptions for managing non-error conditions, I strongly recommend that you avoid the practice; just be aware that other programmers may use this technique, and be prepared to deal with it. If, for example, I didn�t define a catch (LookupFailed) block for my table-searching code, the exception would flow backward through the call chain, executing a catch-all block or the terminate function -- clearly undesirable behavior for an exception that really isn�t an error.
Standard C++ Exceptions
Standard C++ defines, in the header file stdexcept, a core class hierarchy for exception handling. The base class, exception, is defined as follows:
class exception
{
public:
// constructor
exception();
// copy constructor
exception (const exception & ex) throw();
// assignment operator
exception & operator = (const exception & ex) throw();
// virtual destructor
virtual ~exception() throw();
// explanation of exception
virtual const char * what() const throw();
};
No member of exception is allowed to throw an exception, as designated by the throw() declaration attached to each function declaration. All exceptions thrown by components of the C++ Standard library are derived from exception. Thus, a simple segment of code like this
try
{
// program code
}
catch (const exception & ex)
{
cout << �exception: � << ex.what();
}
would trap and display information about any exception thrown by classes and functions in the Standard C++ library.
The hierarchy of exceptions is broken into a two subsets, based on the following pair of classes:
class logic_error : public exception
{
public:
logic_error (const string & what_arg) throw();
};
class runtime_error : public exception
{
public:
runtime_error (const string & what_arg) throw();
};
Each of these classes defines a single constructor, which must include a string argument containing the text to be returned by the inherited exception::what() member function. According to the Standard, a logic_error reports an problem that is �detectable� before a program executes -- and yes, that�s exactly what the official document states. The example is of �a violation of logical preconditions or class invariants.� From logic_error, the Standard derives a set of four classes that further clarify its intent: domain_error, invalid_argument, length_error, and out_of_range.
Runtime errors occur during program execution; two specific varieties defined in the Standard are range_error and overflow_error. The standard is quite unclear as to the precise meaning of these exceptions, beyond the obvious implications of their names. Nor does the standard define why it assigns types to specific categories of logical errors and runtime errors. A domain error might occur when a program is asked to perform an impossible calculation (e.g., calculating the square root of -1) -- but such an error could occur during the construction of static object (a �logic error� during program initialization) or during program execution (a run-time error). And the definition of an �overflow� exception seems incomplete without a counterpart to handle �underflow� conditions.
Given those caveats, however, I've come to use the standard exceptions as the basis of my own exception hierarchies. In discussions with various people involved in the definition of Standard C++, I've come to understand that these exceptions were meant to provide a foundation for user-defined exceptions.
Memory Allocation
The C++ Standard expands the error-trapping abilities of the memory allocation operator new with the definition of the bad_alloc exception.
class bad_alloc : public exception
{
public:
// constructor
bad_alloc() throw();
// copy constructor
bad_alloc (const bad_alloc & ba) throw();
// assignment
bad_alloc & operator = (const bad_alloc & ba) throw();
// destructor
virtual ~bad_alloc() throw();
// reporting
virtual const char * what() const throw();
};
The original definition of C++ defined the new operator as returning a NULL pointer when the requested memory could not be allocated; some implementations also supported an error-trapping exception named xalloc. The Standard supports both NULL-return and exception-based error reporting from new, by overloading the memory allocation operator:
struct throw { }; // empty structure
// new w/exceptions
void * operator new(size_t size) throw (bad_alloc);
void * operator new[](size_t size) throw (bad_alloc);
// new returning NULL
void * operator new(size_t size, const nothrow & t) throw();
void * operator new[](size_t size, const nothrow & t) throw();
If a requested memory allocation fails, the first two implementations of new throw bad_alloc, unless a prior call was made to set_new_handler with a non-NULL parameter. In other words, if you define a new_handler function, it will be called for memory allocation errors; if no new_handler is set, such errors throw bad_alloc.
Most older C++ code follows the C programming model by checking the value returned by new for a NULL resulting from a failure to allocate memory. To keep using that style of error checking, the second pair of new definitions above returns NULL upon failure, unless a new_handler function is set via set_new_handler. To invoke the NULL-returning form of new, include an extra parameter in your statement.
int * iarray = new(nothrow()) int [1000];
if (iarray == NULL)
{
cout << �could not allocate iarray\n�;
exit(EXIT_FAILURE);
}
Calling new without a nothrow() parameter results in a bad_alloc exception if the requested memory cannot be allocated and a new_handler is not set.
int * iarray;
try {
iarray = new int [1000];
}
catch (bad_alloc)
{
cout << �could not allocate iarray\n�;
exit(EXIT_FAILURE);
}
So what�s the advantage of using the exception-throwing version of new? Trapping bad_alloc allows you to centralize the processing of errors, as well as making your code more succinct and readable. For example, this section of code
#include <new>
const size_t szBuf = 1024;
int * iBuf;
char * cBuf;
bool InitApp();
int main()
{
if (InitApp() == false)
{
cout << �could not initialize application\n�;
return EXIT_FAILURE;
}
// other code
// success!
return EXIT_SUCCESS;
}
bool InitApp()
{
// allocate and check for error return
iBuf = new(nothrow()) int [szBuf];
if (iBuf == NULL)
return false;
// allocate and check for error return
cBuf = new(nothrow()) char [szBuf];
if (cBuf == NULL)
return false;
else
return true;
}
could be rewritten using exceptions, like this:
#include <new>
const size_t szBuf = 1024;
int * iBuf;
char * cBuf;
void InitApp();
int main()
{
try {
InitApp();
}
catch (exception & ex)
{
cout << �could not initialize application\n�
<< ex.what() << endl;
return EXIT_FAILURE;
}
// other code
return EXIT_SUCCESS;
}
void InitApp()
{
// allocate buffers
iBuf = new int [szBuf];
cBuf = new char [szBuf];
}
Notice how much �cleaner� the InitApp function looks with the error-checking removed. All exceptions thrown in InitApp -- including logic, runtime, and memory allocation errors -- will be caught in main�s catch block, which displays the specifics of the problem. If you prefer to use an exception handler function, the example code above could also be written like this:
#include <new>
const size_t szBuf = 1024;
int * iBuf;
char * cBuf;
void InitApp();
void AllocErr()
{
cout << �memory allocation failure\n�;
exit(EXIT_FAILURE);
}
int main()
{
// assign a new handler function
set_new_handler(AllocErr);
InitApp();
// other code
return EXIT_SUCCESS;
}
bool InitApp()
{
// allocate and check for error return
iBuf = new int [szBuf];
cBuf = new char [szBuf];
}
The only fault I find with the schemes above is that their variety; in a multi-programmer project, or when working with third-party class libraries, you�ll need to be aware of exactly which technique is in use, tailoring your code accordingly.
Final Thoughts
Signals and exceptions don't mix well, and should be considered seperately. While you can define an exception-based �wrapper� for signals, such code is not portable, because C++ does not guarantee that a signal-handling function is able to interact with any other part of a program. Creating a signal handler that throws an exception, for example, is undefined behavior in Standard C++.
C++�s exception mechanism uses �termination semantics�, meaning that the occurrence of an exception causes the program to terminate its current actions before seeking a handler. Some programming languages and operating systems (Windows NT, in particular) support the concept of resumption, where an exception handler can return program execution to the point where the exception was thrown. The idea behind resumption is that the handler can try to fix the problem and then allow the program to continue. However, after reviewing current programming practice, the C++ Standardization committee decided that resumption was used only rarely, and that termination was a simpler way of handling exceptions.
A common misconception is that exceptions add substantial overhead to a program. In fact, exceptions may be more efficient than old-fashioned return-value checking. Throwing an exception allows us to write a central exception trap, as opposed to testing every time we perform a potentially-erroneous action. Instead of populating programs with lots of �if this is broke do that� logic, we can centralize and structure our error handlers.

