The C++ language provides built-in support for handling anomalous situations, known as “exceptions,” which may occur during the execution of your program. The try, throw, and catch statements have been added to the C++ language to implement exception handling. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code which is outside the normal flow of control. The Microsoft C++ compiler implements the C++ exception handling model based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++.
Syntax
try-block :
try compound-statement handler-list
handler-list :
handler handler-listopt
handler :
catch ( exception-declaration ) compound-statement
exception-declaration :
type-specifier-list declarator
type-specifier-list abstract-declarator
type-specifier-list
...
throw-expression :
throw assignment-expressionopt
The compound-statement after the try clause is the guarded section of code. The throw-expression “throws” (raises) an exception. The compound-statement after the catch clause is the exception handler, and “catches” (handles) the exception thrown by the throw-expression. The exception-declaration statement indicates the type of exception the clause handles. The type can be any valid data type, including a C++ class. If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including a C exception. Such a handler must be the last handler for its try block.
The operand of throw is syntactically similar to the operand of a return statement.
Note Microsoft C++ does not support the function throw signature mechanism, as described in section 15.5 of the ANSI C++ draft. In addition, it does not support function-try-block described in section 15 of the ANSI C++ draft.
Execution proceeds as follows:
terminate
is called. If an exception occurs after throwing the exception, but before the unwind begins, terminate
is called. goto
statement or a case
label in a switch
statement.The following is a simple example of a try block and its associated catch handler. This example detects failure of a memory allocation operation using the new operator. If new is successful, the catch handler is never executed:
#include <iostream.h>
int main()
{
char *buf;
try
{
buf = new char[512];
if( buf == 0 )
throw "Memory allocation failure!";
}
catch( char * str )
{
cout << "Exception raised: " << str << '\n';
}
// ...
return 0;
}
The operand of the throw expression specifies that an exception of type char *
is being thrown. It is handled by a catch handler that expresses the ability to catch an exception of type char *
. In the event of a memory allocation failure, this is the output from the preceding example:
Exception raised: Memory allocation failure!
The real power of C++ exception handling lies not only in its ability to deal with exceptions of varying types, but also in its ability to automatically call destructor functions during stack unwinding, for all local objects constructed before the exception was thrown.
The following example demonstrates C++ exception handling using classes with destructor semantics:
#include <iostream.h>
void MyFunc( void );
class CTest
{
public:
CTest(){};
~CTest(){};
const char *ShowReason() const { return "Exception in CTest class."; }
};
class CDtorDemo
{
public:
CDtorDemo();
~CDtorDemo();
};
CDtorDemo::CDtorDemo()
{
cout << "Constructing CDtorDemo.\n";
}
CDtorDemo::~CDtorDemo()
{
cout << "Destructing CDtorDemo.\n";
}
void MyFunc()
{
CDtorDemo D;
cout<< "In MyFunc(). Throwing CTest exception.\n";
throw CTest();
}
int main()
{
cout << "In main.\n";
try
{
cout << "In try block, calling MyFunc().\n";
MyFunc();
}
catch( CTest E )
{
cout << "In catch handler.\n";
cout << "Caught CTest exception type: ";
cout << E.ShowReason() << "\n";
}
catch( char *str )
{
cout << "Caught some other exception: " << str << "\n";
}
cout << "Back in main. Execution resumes here.\n";
return 0;
}
This is the output from the preceding example:
In main.
In try block, calling MyFunc().
Constructing CDtorDemo.
In MyFunc(). Throwing CTest exception.
Destructing CDtorDemo.
In catch handler.
Caught CTest exception type: Exception in CTest class.
Back in main. Execution resumes here.
Note that in this example, the exception parameter (the argument to the catch clause) is declared in both catch handlers:
catch( CTest E )
// ...
catch( char *str )
// ...
You do not need to declare this parameter; in many cases it may be sufficient to notify the handler that a particular type of exception has occurred. However, if you do not declare an exception object in the exception-declaration, you will not have access to that object in the catch handler clause.
A throw-expression with no operand re-throws the exception currently being handled. Such an expression should appear only in a catch handler or in a function called from within a catch handler. The re-thrown exception object is the original exception object (not a copy). For example:
try
{
throw CSomeOtherException();
}
catch(...) // Handle all exceptions
{
// Respond (perhaps only partially) to exception
// ...
throw; // Pass exception to some other handler
}