C++ Exceptions and exception handling
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.
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.
Standard exceptions
The C++ standard library provides a base class specifically designed to declare objects to be thrown as exceptions. To make use of the standard exceptions we have to include the exception header file.
All of the exceptions thrown by parts of the C++ Standard library will throw exceptions derived from the std::exception class. These exceptions are:
bad_alloc
A bad_alloc is thrown by new if an allocation failure occurs.
bad_cast
A bad_cast is thrown by dynamic_cast when it fails with a referenced type.
bad_exception
A bad_exception is thrown when an exception type doesn’t match any catch
bad_typeid
A bad_typeid is thrown by typeid
ios_base::failure
An ios_base::failure is thrown by functions in the iostream library.
So let’s use it in an example, but be warned this example can lock your computer! It should not happen, but it might.
#include<iostream>
#include <exception>
using namespace std;
int main()
{
try
{
int * my_array1= new int[100000000];
int * my_array2= new int[100000000];
//int * my_array3= new int[100000000];
//int * my_array4= new int[100000000];
//add more if needed.
}
catch (bad_alloc&)
{
cout << "Error allocating the requested memory." << endl;
}
return 0;
}
Note: you should add more my_array’s until exception occurs. You could also add some free statements in the catch block, freeing up already claimed memory.
It is recommended to use try blocks if you use dynamic memory allocation. This way you are in control if an allocation fails. For example: you unload all used resources and then end the program.
That is all for this tutorial.
Good for c++ programming
very nice for exception handling