Exceptions are the way of flagging unexpected conditions or errors that have occurred in C++ program.
Exception Mechanism
so far we have handled error conditions by using the if statement to test some expressions and then executing specific code to deal with the error. C++ Language provides a good mechanism to tackle these conditions. The exception mechanism
uses three keywords.
- try – It identifies a code block in which an exception can occur
- catch – Identifies a block of code in which the exception is handled
- throw – It causes an exception condition to be originated
Introduction to Exception Handling
In this tutorial we will be discussing some aspects of C++ exception handling. To start this discussion, let’s consider a simple example. Suppose that you are writing a program to manipulate calendar dates, and want to check whether a given year is in the 20th century.
Using exceptions, one way to do this might be:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <IOSTREAM.H> class DateException { char* err; public: DateException(char* s) {err = s;} void print() const {cerr << err << endl; } }; // a function that operates on dates void g(int date) { if (date < 1900) throw DateException("date < 1900"); if (date > 1999) throw DateException("date > 1999"); // process date ... } // some code that uses dates void f() { g(1879); } int main() { try { f(); } catch (const DateException& de) { de.print(); return 1; } return 0; } |
The basic idea here is that we have a try block:
1 2 3 4 | try { f(); } |
Within this block, we execute some code, in this case a function call f().
Then we have a list of one or more handlers:
1 2 3 4 | catch (DateException de) { de.print(); return 1; } |
If an abnormal condition arises in the code, we can throw an exception:
1 2 | if (date < 1900) throw DateException("date < 1900"); |
and have it caught by one of the handlers at an outer level, that is, execution will continue at the point of the handler, with the execution stack unwound.
An exception may be a class object type such as DateException, or a fundamental C++ type like an integer. Obviously, a class object type can store and convey more information about the nature of the exception, as illustrated in this example. Saying:
throw -37;
will indeed throw an exception, which may be caught somewhere, but this idiom is not particularly useful.
What if the handler we declare is changed slightly, as in:
1 2 3 4 | catch (DateException* de) { de->print(); return 1; } |
In this case, because an object of type DateException is thrown, rather than a DateException* (pointer), no corresponding handler will be found in the program. In that case, the runtime system that handles exception processing will call a special library function terminate(), and the program will abort. One way to avoid this problem is to say:
1 2 3 4 5 6 7 8 9 10 11 | main() { try { body_of_program(); } catch (...) { // all exceptions go through here return 1; } return 0; } |
where “…” will catch any exception type.
We will explore various details of exception handling later, but one general comment is in order. C++ exceptions are not the same as low-level hardware interrupts, nor are they the same as UNIX signals such as SIGTERM. And there’s no linkage between exceptions such as divide by zero (which may be a low-level machine exception) and C++ exceptions.