Exception Handling in C++

What is an exception?

Exception is an event that happens when unexpected circumstances appear. It can be a runtime error or you can create an exceptional situation programmatically.

Exception handling consists in transferring control from the place where exception happened to the special functions (commands) called handlers.

How to handle exceptions?

Exceptions are handled by using try/catch block. The code that can produce an exception is surrounded with try block. The handler for this exception is placed in catch block:

Try/catch block uses the following syntax:

try
{
	//code that can produce error
}
catch (ExceptionType e)
{
	//exception handler 
}

Example of an exception:

Look on the following example:

//use a vector
vector<int> arr;

//push two elements into vector
arr.push_back(4);
arr.push_back(7);

//try to access the third element that does not exist
arr.at(2);

This code compiles without errors.  Nevertheless, if you try to run this program, you will get an error:

 

You are trying to access an element of a vector that does not exist. at(int) member function of vector throws exception when it is called.

Example of exception handling.

You can re-write this program using exception-handling mechanism:

//use a vector
vector<int> arr;

//push two elements into vector
arr.push_back(4);
arr.push_back(7);

//try to access the third element that does not exist
try
{
	arr.at(2);
}
catch (...)//catch all exceptions
{
	cout << "Exception happened" << endl;
}

As you can see, exception handling makes your code safer and protects your program from runtime errors.

Built-in exceptions

C++ provides a range of built in exceptions. The base class for all exceptions classes is exception

The information about happened exception is provided by what() member function of  the exception class:

//try to access the third element that does not exist
try
{
	arr.at(2);
}
catch (exception& e)//catch all exceptions
{
	cout << "Exception happened: " << e.what() << endl;
}

In this case, you will get following output:

Exception happened: invalid vector<T> subscript

All the Standard Exceptions are listed in the following diagram:

Short description of these exceptions is provided in these tables:

Exceptions derived directly from exception class:

 bad_alloc Happens when there is a failure of memory allocation
 bad_cast Is thrown when dynamic_cast is used incorrect
 bad_exception Exception that is thrown by unexpected handler
 bad_function_call Thrown when an empty (not implemented) function is called
 bad_typeid Thrown by typeid function
 bad_weak_ptr Exception that can be thrown by shared_ptr class constructor
 ios_base::failure Base class for all the stream exceptions
 logic_error Base class for some logic error exceptions
 runtime_error Base class for some runtime error exceptions

 

Exceptions derived indirectly from exception class through logic_error:

 domain_error Thrown when an error of function domain happens
 future_error Reports an exception that can happen in future objects(See more info about future class)
 invalid_argument Exception is thrown when invalid argument is passed
 length_error Is thrown when incorrect length is set
 out_of range error Is thrown when out of range index is used

 

Exceptions derived indirectly from exception class through runtime_error:

 overflow_error Arithmetic overflow exception
 range_error Signals range error in computations
 system_error Reports an exception from operating system
 underflow_error Arithmetic underflow exceptions

 

How to throw an exception

There is a possibility to throw an exception. It can be done by using throw keyword.

Look on example:

double divide(double a, double b)
{
	if (b == 0)//division by zero!!!!
		throw "Division by zero";
	else
		return a / b;
}

Function divide throws an exception in form of string, when denominator is zero. In this case, the execution of function is terminated and exception is thrown to the place where function was called. Now, try to call this function with incorrect parameter:

try
{
	double res = divide(1, 0);
}
catch (char* c)
{
	cout << c;
}

This produces the following output:

Division by zero

How to extend exception class?

Sometimes, you will need to create your own exception classes. This can be done for different purposes. For example, you want to send some information from the place, where exception happened, to the catch block. It can be done by extending class exception. In this case, you can create a constructor for the derived class and override its member function what().

class ZeroDivisionException :public exception
{
public:
	ZeroDivisionException(int data)
	{
		someData = data;
	}
	//override what function
	const char* what()
	{
		return "Zero division error";
	}
	int someData;
};

ZeroDivisionException class stores an integer data member someData. Now we can get the information from the place, where exception happened, in the catch block. For this purpose, we will re-write divide function:

double divide(double a, double b)
{
	if (b == 0) //division by zero!!!!
		throw ZeroDivisionException(a);
	else
		return a/b;
}

Parameter a is passed and returned back from the function. We can use it in catch block:

try
{
	double res = divide(1, 0);
}
catch (ZeroDivisionException e)
{
	cout << e.what() << endl;
	cout << "Trying to divide " << e.someData << " by zero" << endl;
}

The output is

Zero division error

Trying to divide 1 by zero

Exceptions provide a powerful and efficient mechanism to control errors and make your programs safer.

Translate »