Exception Handling

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. The principal advantage of exception handling is that it automates much of the error-handling code that previously had to be coded “by hand” in any large program.

What are Exceptions?

Exceptions are situations which must be avoided during program executions. Exceptions are caused by errors, invalid inputs or invalid processing. Exceptions can lead to either program termination or generating unexpected outputs.

In general, it is assumed that exceptions are errors but this is not always true. We can state:

All errors are exceptions but not necessarily all exceptions are errors.

Exceptions can be handled or avoided by a simple control statement such as an if-else statement, but most languages provide a separate mechanism of exception handling.

Exception Handling

Exception handling is a process of handling exceptional situations that may occur in a program due to the above stated reasons in such a way that:

  • The program will terminate gracefully i.e. it will give a proper message and then will terminate the program.
  • After giving the proper message stating the reason of the exception the program continues to execute after correcting the error.

In the C++ language, exception handling is performed using the following keywords:

  • try
  • catch
  • throw
  • throws

Take a look at the process of exception handling:

To catch exceptions we must place a portion of code under exception inspection. We can do this by putting that portion of code in a try block. So, when an exceptional circumstance arises (within that block) an exception is thrown. This in turn transfers the control to the exception handler. If there are no exceptions thrown, the code will continue normally and all handlers are ignored.

try {
 // try block
 }
 catch (type1 arg) {
 // catch block
 }
 catch (type2 arg) {
 // catch block
 }
 catch (type3 arg) {
 // catch block
 }
 ..
 .
 catch (typeN arg) {
 // catch block
 }

The try can be as short as a few statements within one function or as all encompassing as enclosing the main() function code within a try block (which effectively causes the entire program to be monitored).

Advantages of Exception Handling

Following are main 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 any 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 caller. If the caller chooses not to catch them, then the exceptions are handled by 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 exception. We can create a hierarchy of exception objects, group exceptions in namespaces or classes, categorize them according to types.

Take a look at an example:

	#include<iostream>
	using namespace std;

	int main ()
	{
		try
		{
			throw 5;
		}

		catch (int a)
		{
			cout << "An exception occurred!" << endl;
			cout << "Exception number is: " << a << endl;
		}
		return 0;
	}

As you can see, the code under exception handling is enclosed in a try block. We simply throw an exception with the statement: throw 5;

The throw expression can accept on parameter, which is passed as an argument to the exception handler.As you can see, in this example we passed the integer value five.

We declared the exception handler with the catch keyword. As you can see, the catch format looks the same as a normal function. The catch statement always has at least one parameter.

The type of the parameter used in the catch statement must be the same as the type used in the throw statement. If it is not, the exception is not caught. For this reason it is possible to use multiple exception handlers. We just use different catch statements which in turn use different parameter types. Only the handler that matches its type with the argument specified in the throw statement is executed.

Let’s take a look at such an example:

	#include<iostream>
	#include <string>
	using namespace std;

	int main()
	{
		int num;
		string str_bad = "wrong number used";
		cout << "Input 1 or 2: ";
		cin >> num;

		try
		{
			if ( num == 1 )
			{
				throw 5;
			}
			if ( num == 2 )
			{
				throw 1.1f;
			}
			if ( num != 1 || num != 2 )
			{
				throw str_bad;
			}
		}

		catch (int a)
		{
			cout << "An exception occurred!" << endl;
			cout << "Exception number is: " << a << endl;
		}
		catch (float b)
		{
			cout << "An exception occurred!" << endl;
			cout << "Exception number is: " << b << endl;
		}
		catch (...)
		{
			cout << "A default exception occurred!" << endl;
			cout << "Why? : " << str_bad << endl;
		}
		return 0;
	}

The program above will throw an exception after you input something. If the number is a 1 then an integer is thrown. If the input is a 2 then a float is thrown. If it is neither of these two (not an integer or float) the default exception handler is used. This default exception handler uses the ellipsis (…) as the parameter of catch. That handler will catch any exception no matter what the type of the throw exception is. (In this case a string is used.)

It is possible to nest try-catch blocks, but you have to test it very well because it is easy to make a mistake which in turn can lead to an unexpected result.

Exception and functions

If we declare a function, we can limit the exception type that the function might throw. We can do this by adding a throw suffix to the function declaration. For example:

int a_function (int param) throw(int);
int a_function (int param) throw();
int a_function (int param);

The first function of the examples above takes one argument of the type integer and will return an integer.
The only exception that this function might throw is an exception of type int.

The second function also takes one argument of the type integer and will return an integer. The function may not throw exceptions, because there is no type specified between the round brackets. (No type specified means that the function is not allowed to throw exception.)

The last function may throw exception of any type.