Exception handling allows you to manage run-time errors in an orderly fashion. Using exception handling, your program can automatically invoke an error-handling routine when an error occurs. C++ exception handling is built upon three keywords: try, catch, and throw. program statements that you want to monitor for exceptions are contained in a try block. If an exception (i.e., an error) occurs within the try block, it is thrown (using throw). The exception is caught, using catch, and processed. Code that you want to monitor for exceptions must have been executed from within a try block. (Functions called from within a try block may also throw an exception.) Exceptions that can be thrown by the monitored code are caught by a catch statement, which immediately follows the try statement in which the exception was thrown.
The general form of try and catch are shown here.try
{
// try block
}
catch (type1 arg)
{
// catch block
}
catch (type2 arg)
{
// catch block
}
catch (type3 arg)
{
// catch block
}...
catch (typeN arg)
{
// catch block
}
// This example will not work.
#include <iostream>
using namespace std;
void main()
{
cout << "Start\n";
try
{
cout << "Inside try block\n";
throw 100; // throw an error
cout << "This will not execute";
}
catch (double i)
{
cout << "Caught an exception -- value is: ";
cout << i << "\n";
}
cout << "End";
}
/* Throwing an exception from a function outside the try block. */
#include <iostream>
using namespace std;
void Xtest(int test)
{
cout << "Inside Xtest, test is: " << test << "\n";
if(test)
throw test;
}
void main()
{
cout << "Start\n";
try
{
cout << "Inside try block\n";
Xtest(0);
Xtest(1);
Xtest(2);
}
catch (int i)
{
cout << "Caught an exception -- value is: ";
cout << i << "\n";
}
cout << "End";
}
Catching Class Types
An exception can be of any type, including class types that you create. Actually, in real-world programs, most exceptions will be class types rather than built-in types. Perhaps the most common reason that you will want to define a class type for an exception is to create an object that describes the error that occurred. This information can be used by the exception handler to help it process the error.
// Catching class type exceptions.
#include <iostream>
#include <string>
using namespace std;
class MyException
{
public:
char str_what[80];
int what;
MyException()
{
*str_what = 0;
what = 0;
}
MyException(char *s, int e)
{
strcpy(str_what, s);
what = e;
}
};
void main()
{
int i;
try
{
cout << "Enter a positive number: ";
cin >> i;
if(i<0 br=""> throw MyException("Not Positive", i);
}
catch (MyException e)
{
// catch an error
cout << e.str_what << ": ";
cout << e.what << "\n";
}
}
Using Multiple catch Statements
You can have more than one catch associated with a try. each catch must catch a different type of exception.
For example, this program catches both integers and strings.
#include <iostream>
using namespace std;
// Different types of exceptions can be caught.
void Xhandler(int test)
{
try
{
if(test)
throw test;
else
throw "Value is zero";
}
catch(int i)
{
cout << "Caught Exception #: " << i << '\n';
}
catch(const char *str)
{
cout << "Caught a string: ";
cout << str << '\n';
}
}
void main()
{
cout << "Start\n";
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << "End";
}
Handling Derived-Class Exceptions
when trying to catch exception types that involve base and derived classes because a catch clause for a base class will also match any class derived from that baseThus, if you want to catch exceptions of both a base class type and a derived class type, put the derived class first in the catch sequence..
// Catching derived classes.
#include <iostream>
using namespace std;
class B
{
};
class D: public B
{
};
void main()
{
D derived;
try
{
throw derived;
}
catch(B b)
{
cout << "Caught a base class.\n";
}
catch(D d)
{
cout << "This won't execute.\n";
}
}
Catching All Exceptions
In some circumstances you will want an exception handler to catch all exceptions instead of just a certain type. This is easy to accomplish.
Simply use this form of catch.
catch(...)
{
// process all exceptions
}
// This example catches all exceptions.
#include <iostream>
using namespace std;
void Xhandler(int test)
{
try
{
if(test==0)
throw test; // throw int
if(test==1)
throw 'a'; // throw char
if(test==2)
throw 123.23; // throw double
}
catch(...)
{
// catch all exceptions cout << "Caught One!\n";
}
}
void main()
{
cout << "Start\n";
Xhandler(0);
Xhandler(1);
Xhandler(2);
cout << "End";
}
Restricting Exceptions
You can restrict the type of exceptions that a function can throw outside of itself. In fact, you can also prevent a function from throwing any exceptions whatsoever. To accomplish these restrictions, you must add a throw clause to a function definition.
The general form of this is shown here:
ret-type func-name(arg-list) throw(type-list)
{
// ...
}
// Restricting function throw types.
#include <iostream>
using namespace std;
// This function can only throw ints, chars, and doubles.
void Xhandler(int test)
throw(int, char, double)
{
if(test==0)
throw test; // throw int
if(test==1)
throw 'a'; // throw char
if(test==2)
throw 123.23; // throw double
}
void main()
{
cout << "start\n";
try
{
Xhandler(0); // also, try passing 1 and 2 to Xhandler()
}
catch(int i)
{
cout << "Caught an integer\n";
}
catch(char c)
{
cout << "Caught char\n";
}
catch(double d)
{
cout << "Caught double\n";
}
cout << "end";
}
Rethrowing an Exception
If you wish to rethrow an expression from within an exception handler, you may do so by calling throw, by itself, with no exception. This causes the current exception to be passed on to an outer try/catch sequence.
// Example of "rethrowing" an exception.
#include <iostream>
using namespace std;
void Xhandler()
{
try
{
throw "hello"; // throw a char *
}
catch(const char *)
{ // catch a char *
cout << "Caught char * inside Xhandler\n";
throw ; // rethrow char * out of function
}
}
C++ void main()
{
cout << "Start\n";
try
{
Xhandler();
}
catch(const char *)
{
cout << "Caught char * inside main\n";
}
cout << "End";
}
Applying Exception Handling
Exception handling is designed to provide a structured means by which your program can handle abnormal events. This implies that the error handler must do something rational when an error occurs. For example, consider the following simple program. It inputs two numbers and divides the first by the second. It uses exception handling to manage a divide-by-zero error.
#include <iostream>
using namespace std;
void divide(double a, double b);
void main()
{
double i, j;
do
{
cout << "Enter numerator (0 to stop): ";
cin >> i;
cout << "Enter denominator: ";
cin >> j;
divide(i, j);
}
while(i != 0);
}
void divide(double a, double b)
{
try
{
if(!b)
throw b; // check for divide-by-zero
cout << "Result: " << a/b << endl;
}
catch (double b)
{
cout << "Can't divide by zero.\n";
}
}