Exception Handling
Exceptions are runtime anomalies or abnormal conditions that a program encounters
during its execution.
There are two types of exceptions:
a)Synchronous,
b)Asynchronous (i.e., exceptions which are beyond the program’s control, such as
disc failure, keyboard interrupts etc.).
Why Exception Handling?
Advantages of exception handling over traditional error handling:
1) Separation of Error Handling code from Normal Code: In traditional error
handling codes, there are always if-else conditions to handle errors. These conditions
and the code to handle errors get mixed up with the normal flow. This makes the
code less readable and maintainable. With try/catch blocks, the code for error
handling becomes separate from the normal flow.
2) Functions/Methods can handle only the exceptions they choose: A function can
throw many exceptions, but may choose to handle some of them. The other
exceptions, which are thrown but not caught, can be handled by the caller. If the
caller chooses not to catch them, then the exceptions are handled by the caller of the
caller.
In C++, a function can specify the exceptions that it throws using the throw
keyword. The caller of this function must handle the exception in some way (either
by specifying it again or catching it).
3) Grouping of Error Types: In C++, both basic types and objects can be thrown as
exceptions. We can create a hierarchy of exception objects, group exceptions in
namespaces or classes and categorize them according to their types.
Exception Handling
C++ provides the following specialized keywords for this purpose:
try: Represents a block of code that can throw an exception. We can define a block
of code to be tested for errors while it is being executed.
catch: Represents a block of code that is executed when a particular exception is
thrown.
throw: Used to throw an exception. Also used to list the exceptions that a function
throws but doesn’t handle itself.
Example1
#include <iostream>
using namespace std;
int main()
{
int x = -1;
cout << "Before try \n";
try {
cout << "Inside try \n";
if (x < 0)
{
throw x;
cout << "After throw (Never executed) \n";
}
}
catch (int x ) {
cout << "Exception Caught \n";
}
cout << "After catch (Will be executed) \n";
return 0;
}
Output:
Before try
Inside try
Exception Caught
After catch (Will be executed)
Example2
include <iostream>
using namespace std;
int main()
{
try {
throw 10;
}
catch (char *excp) {
cout << "Caught " << excp;
}
catch (...) {
cout << "Default Exception\n";
}
return 0;
}
Output:
Default Exception
Example3
If an exception is thrown and not caught anywhere, the program terminates abnormally. For
example, in the following program, a char is thrown, but there is no catch block to catch the
char.
#include <iostream>
using namespace std;
int main()
{
try {
throw 'a';
}
catch (int x) {
cout << "Caught ";
}
return 0;
}
Output:
terminate called after throwing an instance of 'char'
Example 4
In C++, try/catch blocks can be nested. Also, an exception can be re-thrown using throw; .
#include <iostream>
using namespace std;
int main()
{
try {
try {
throw 20;
}
catch (int n) {
cout << "Handle Partially ";
throw; // Re-throwing an exception
}
}
catch (int n) {
cout << "Handle remaining ";
}
return 0;
}
Output:
Handle Partially Handle remaining
Example 5
When an exception is thrown, all objects created inside the enclosing try block are
destroyed before the control is transferred to the catch block .
#include <iostream>
using namespace std;
class Test {
public:
Test() { cout << "Constructor of Test " << endl; }
~Test() { cout << "Destructor of Test " << endl; }
};
int main()
{
try {
Test t1;
throw 10;
}
catch (int i) {
cout << "Caught " << i << endl;
}
Output:
Constructor of Test
Destructor of Test
Caught 10