Exceptions provide a way to react to exceptional circumstances (like runtime errors) in programs by transferring control to special code blocks called handlers.
To catch exceptions, a portion of code is placed under exception inspection. This is done by enclosing that portion of code in a try
-block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler block. If no exception is thrown, the code continues normally and all handlers are ignored.
An exception is thrown by using the throw
keyword from inside the try
block. Exception handlers are declared with the keyword catch
, which must be placed immediately after the try
block:
#include <iostream>
#include <stdexcept>
#include <cstdlib>
using std::cin;
using std::cout;
using std::endl;
using std::invalid_argument;
int main(int argc, char* argv[])
{
int value;
try
{
if (argc == 1)
throw invalid_argument("No command line arguments specified");
cout << argv[1] << endl;
}
catch (const invalid_argument& e)
{
cout << "Error: " << e.what() << endl;
}
// Following code...
...
return 0;
}
The code under exception inspection is enclosed in a try
block. In this example this code simply throws an exception if there are no command-line arguments specified when the program is run. A throw
expression accepts an expression (in this case, an unnamed object of the class invalid_argument
), which is passed as an argument to the exception handler.
invalid_argument
is a standard library exception class defined in the header file stdexcept
. The constructor for the class takes a string argument, which can later be accessed by calling the what()
member function of the exception object passed to the exception handler.
The exception handler is declared with the catch
keyword immediately after the closing brace of the try
block. The syntax for catch
is similar to a regular function with one parameter. The type of this parameter is very important, since the type of the argument passed by the throw
expression is checked against it, and only in the case that they match is the exception caught by that handler.
In the example above, if no command line arguments are specified, the exception is thrown and program control is transferred to the catch
handler block that matches the data type invalid_argument
. An error message is printed and then the program continues execution after the try-catch
structure, not after the throw
statement that threw the exception.
If at least one argument is specified after the program name when the program is run, then no exception is thrown and the argument's value is printed. The catch
block is skipped entirely and the program continues execution after the try-catch
structure.
Multiple handlers (i.e., catch
expressions) can be chained; each one with a different parameter type. Only the handler whose argument type matches the type of the exception specified in the throw
statement is executed.
If an ellipsis (...)
is used as the parameter of catch
, that handler will catch an exception of any data type. This can be used as a default handler that catches all exceptions not caught by other handlers:
try
{
// Code that could throw an exception
}
catch (const overflow_error& e)
{
cout << "Invalid argument\n" <<;
}
catch (const underflow_error& e)
{
cout << "Out of range\n" <<;
}
catch (...)
{
cout << "Default exception\n";
}
In this case, the last handler would catch any exception thrown of a type that is neither overflow_error
nor underflow_error
.
It is also possible to nest try-catch
structures within an outer try
block. In that case, we have the option of an inner catch
block simply passing an exception to its enclosing try-catch
structure. This is done using the expression throw;
with no arguments. For example:
try
{
try
{
// Code that could throw an exception
}
catch (const out_of_range& e)
{
throw;
}
}
catch (...)
{
cout << "Exception occurred\n";
}
A handler block may respond to a caught exception in a variety of ways, depending on the needs of the application. Some possible responses include:
catch
blockPractically any C++ data type can be used in a throw
expression, but objects of class types are probably the most commonly used. The standard library defines a number of exception classes in the header file <stdexcept>
, some of which are briefly described below. This list is not exhaustive.
Exception | Description |
---|---|
exception
|
Base class for standard exceptions. All of the other exception classes listed are directly or indirectly derived from this class. |
logic_error
|
Derived class of exception . Serves as the base class for logic error exceptions, including domain_error , invalid_argument , length_error , and out_of_range .
|
runtime_error
|
Derived class of exception . Serves as the base class for runtime error exceptions, including overflow_error and underflow_error .
|
bad_alloc
|
Derived class of exception . Thrown by new and new[] on allocation failure
|
bad_cast
|
Derived class of exception . Thrown by dynamic_cast when it fails in a dynamic cast
|
domain_error
|
Derived class of logic_error . Can be thrown to report domain errors, that is, situations where the inputs are outside of the domain on which an operation is defined. The standard library components do not throw this exception.
|
invalid_argument
|
Derived class of logic_error . Can be thrown to report an invalid argument. Some components of the standard library throw exceptions of this type.
|
length_error
|
Derived class of logic_error . Can be thrown to report a length error. Some components of the standard library such as the reserve() member functions of vector and string throw exceptions of this type.
|
out_of_range
|
Derived class of logic_error . Can be thrown to report an argument that is out-of-range. Some components of the standard library such as the at() member functions of vector , string , deque , and array throw exceptions of this type.
|
overflow_error
|
Derived class of runtime_error . Can be thrown to report an arithmetic overflow error. Some components of the standard library throw exceptions of this type.
|
underflow_error
|
Derived class of runtime_error . Can be thrown to report an arithmetic underflow error. The standard library components do not throw this exception.
|