Startertutorials Blog
Tutorials and articles related to programming, computer science, technology and others.
Subscribe to Startertutorials.com's YouTube channel for different tutorial and lecture videos.

Categories: C++ Programming. No Comments on Exception Handling in C++ Programming
5
(1)

This article provides a comprehensive overview of exception handling in C++ programming language along with example programs.

 

Introduction

In programming, it is common for programmers to make mistakes which leads to abnormal conditions called as errors. In general, these errors are of three types: 1) Syntax errors, 2) Logical errors, and 3) Run-time errors.

 

Syntax errors are most frequent type of errors. For example, if we forget to place a semi-colon, it is a syntax error. Logical errors arise when programmer performs a mistake in the logic of a program. For example, in addition of two numbers program, if the programmers places a minus instead of plus, it is a logical error. These are very hard to detect.

 

The last category of errors are the errors which occur while executing the program. These errors are known as run-time errors or exceptions. Exceptions are of two types: 1) Synchronous, and 2) Asynchronous.


Subscribe to our monthly newsletter. Get notified about latest articles, offers and contests.


 

Synchronous exceptions are the run-time exceptions which occur due to the code written by the programmer and they can be handled by the programmer. Asynchronous exceptions are run-time exceptions which occur due to code outside the program.

 

For example, if no memory is available in the RAM, it will lead to out of memory error which is an asynchronous exception. Such asynchronous exceptions cannot be handled. Errors in programs can be illustrated as shown below:

 

types-of-errors

 

Exception Handling

 

Handling synchronous exceptions is known as exception handling. Exception handling deals with detecting run-time exceptions and reporting it to the user for taking appropriate action. C++ provides try, catch, and throw elements for handling exceptions.

 

A try block contains code which might raise exceptions. Syntax of try block is as follows:

 

try
{
	//Code
	...
}

 

A catch block contains code for handling exceptions that may raise in the try block. Syntax of catch block is as follows:

 

catch(Exception-type)
{
	//Code to handle exception
	...
}

 

The throw clause is used to throw an exception which will be caught by the catch block. Syntax of throw clause is as follows:

 

throw exception;

 

Following program handles divide by zero exception:

 

#include<iostream>
using namespace std;
int main()
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	try
	{
		if(b == 0)
			throw b;
		else
			cout<<"Result of a/b = "<<(a/b);
	}
	catch(int b)
	{
		cout<<"b cannot be zero";
	}
	return 0;
}

Input and output for the above program is as follows:
Enter a and b values: 10 0
b cannot be zero

 

Note: If an exception arises and there is no catch block to handle that exceptions, terminate() function will execute which in turn calls abort() function and the execution of program stops abruptly.

 

Multiple Catch Statements

 

A try block can be associated with more than one catch block. Multiple catch statements can follow a try block to handle multiple exceptions. The first catch block that matches the exception type will execute and the control shifts to next statement after all the available catch blocks.

 

A try block should be followed by at least one catch block. If non catch block matches with the exception, then terminate() function will execute. Following program demonstrates handling multiple exceptions using multiple catch statements:

 

#include<iostream>
using namespace std;
int main()
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	try
	{
		if(b == 0)
			throw b;
		else if(b < 0)
			throw "b cannot be negative";
		else
			cout<<"Result of a/b = "<<(a/b);
	}
	catch(int b)
	{
		cout<<"b cannot be zero";
	}
	catch(const char* msg)
	{
		cout<<msg;
	}
	return 0;
}

Input and output for the above program is as follows:

First Run:
Enter a and b values: 10 0
b cannot be zero

Second Run:
Enter a and b values: 10 -5
b cannot be negative

 

Catch All Exceptions

 

While writing programs if the programmer doesn’t know what kind of exception the program might raise, the catch all block can be used. It is used to catch any kind of exception. Syntax of catch all block is as follows:

 

catch(...)
{
	//Code to handle exception
	...
}

 

While writing multiple catch statements care should be taken such that a catch all block should be written as a last block in the catch block sequence. If it is written first in the sequence, other catch blocks will never be executed. Following program demonstrates catch all block:

 

#include<iostream>
using namespace std;
int main()
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	try
	{
		if(b == 0)
			throw b;
		else if(b < 0)
			throw "b cannot be negative";
		else
			cout<<"Result of a/b = "<<(a/b);
	}
	catch(int b)
	{
		cout<<"b cannot be zero";
	}
	catch(...)
	{
		cout<<"Unkown exception in program";
	}
	return 0;
}

Input and output for the above program is as follows:
Enter a and b values: 10 -5
Unkown exception in program

 

Rethrowing an Exception

 

In C++ if a function or a nested try-block does not want to handle an exception, it can rethrow that exception to the function or the outer try-block to handle that exception. Syntax for rethrowing and exception is as follows:

throw;

 

Following program demonstrates rethrowing and exception to outer try-catch block:

 

#include<iostream>
using namespace std;
int main()
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	try
	{
		try
		{
			if(b == 0)
				throw b;
			else if(b < 0)
				throw "b cannot be negative";
			else
				cout<<"Result of a/b = "<<(a/b);
		}
		catch(int b)
		{
			cout<<"b cannot be zero";
		}
		catch(...)
		{
			throw;
		}
	}
	catch(const char* msg)
	{
		cout<<msg;
	}
	return 0;
}

Input and output for the above program is as follows:
Enter a and b values: 10 -2
b cannot be negative

 

In the above program we can see that the exception is raised in the inner try block. The catch all block catches the exception and is rethrowing it to the outer try-catch block where it got handled.

 

Throwing Exceptions in Function Definition

 

A function can declare what type of exceptions it might throw. Syntax for declaring the exceptions that a function throws is as follows:

 

return-type function-name(params-list) throw(type1, type2, ...)
{
	//Function body
	...
}

 

Following program demonstrates throwing exceptions in a function definition:

 

#include<iostream>
using namespace std;
void sum() throw(int)
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	if(a==0 || b==0)
		throw 1;
	else
		cout<<"Sum is: "<<(a+b);
}
int main()
{
	try
	{
		sum();
	}
	catch(int)
	{
		cout<<"a or b cannot be zero";
	}
	return 0;
}

Input and output for the above program is as follows:

Enter a and b values: 5 0
a or b cannot be zero

 

In the above program the sum() function can throw an exception of type int. So, the calling function must provide a catch block for exception of type int.

 

Throwing Exceptions of Class Type

 

Instead of throwing exceptions of pre-defined types like int, float, char, etc., we can create classes and throw those class types as exceptions. Empty classes are particularly useful in exception handling. Following program demonstrates throwing class types as exceptions:

 

#include<iostream>
using namespace std;
class ZeroError {};
void sum()
{
	int a, b;
	cout<<"Enter a and b values: ";
	cin>>a>>b;
	if(a==0 || b==0)
		throw ZeroError();
	else
		cout<<"Sum is: "<<(a+b);
}
int main()
{
	try
	{
		sum();
	}
	catch(ZeroError e)
	{
		cout<<"a or b cannot be zero";
	}
	return 0;
}

Input and output for the above program is as follows:
Enter a and b values: 0 8
a or b cannot be zero

 

In the above program ZeroError is an empty class created for handling exception.

 

Exception Handling and Inheritance

 

In inheritance, while throwing exceptions of derived classes, care should be taken that catch blocks with base type should be written after the catch block with derived type. Otherwise, the catch block with base type catches the exceptions of derived class types too. Consider the following example:

 

#include<iostream>
using namespace std;
class Base {};
class Derived : public Base {};
int main()
{
	try
	{
		throw Derived();
	}
	catch(Base b)
	{
		cout<<"Base object caught";
	}
	catch(Derived d)
	{
		cout<<"Derived object caught";
	}
	return 0;
}

Output for the above program is as follows:

Base object caught

 

You can see that in the above program even though the exception thrown is of the type Derived it is caught by the catch block of the type Base. To avoid that we have to write the catch block of Base type at last in the sequence as follows:

 

#include<iostream>
using namespace std;
class Base {};
class Derived : public Base {};
int main()
{
	try
	{
		throw Derived();
	}
	catch(Derived d)
	{
		cout<<"Derived object caught";
	}
	catch(Base b)
	{
		cout<<"Base object caught";
	}

	return 0;
}

Output of the above program is as follows:

Derived object caught

 

Exceptions in Constructors and Destructors

 

It is possible that exceptions might raise in a constructor or destructors. If an exception is raised in a constructor, memory might be allocated to some data members and might not be allocated for others. This might lead to memory leakage problem as the program stops and the memory for data members stays alive in the RAM.

 

Similarly, when an exception is raised in a destructor, memory might not be deallocated which may again lead to memory leakage problem. So, it is better to provide exception handling within the constructor and destructor to avoid such problems. Following program demonstrates handling exceptions in a constructor and destructor:

 

#include<iostream>
using namespace std;
class Divide
{
	private:
		int *x;
		int *y;
	public:
		Divide()
		{
			x = new int();
			y = new int();
			cout<<"Enter two numbers: ";
			cin>>*x>>*y;
			try
			{
				if(*y == 0)
				{
					throw *x;
				}
			}
			catch(int)
			{
				delete x;
				delete y;
				cout<<"Second number cannot be zero!"<<endl;
				throw;
			}
		}
		~Divide()
		{
			try
			{
				delete x;
				delete y;
			}
			catch(...)
			{
				cout<<"Error while deallocating memory"<<endl;
			}
		}
		float division()
		{
			return (float)*x / *y;
		}
};
int main()
{
	try
	{
		Divide d;
		float res = d.division();
		cout<<"Result of division is: "<<res;
		
	}
	catch(...)
	{
		cout<<"Unkown exception!"<<endl;
	}
	return 0;
}

Input and output for the above program is as follows:

Enter two numbers: 5 0
Second number cannot be zero!
Unkown exception!

 

Advantages of Exception Handling

 

Following are the advantages of exception handling:

  • Exception handling helps programmers to create reliable systems.
  • Exception handling separates the exception handling code from the main logic of program.
  • Exceptions can be handled outside of the regular code by throwing the exceptions from a function definition or by re-throwing an exception.
  • Functions can handle only the exceptions they choose i.e., a function can throw many exceptions, but may choose handle only some of them.

 

A program with exception handling will not stop abruptly. It terminates gracefully by giving appropriate message.

How useful was this post?

Click on a star to rate it!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Suryateja Pericherla

Suryateja Pericherla, at present is a Research Scholar (full-time Ph.D.) in the Dept. of Computer Science & Systems Engineering at Andhra University, Visakhapatnam. Previously worked as an Associate Professor in the Dept. of CSE at Vishnu Institute of Technology, India.

He has 11+ years of teaching experience and is an individual researcher whose research interests are Cloud Computing, Internet of Things, Computer Security, Network Security and Blockchain.

He is a member of professional societies like IEEE, ACM, CSI and ISCA. He published several research papers which are indexed by SCIE, WoS, Scopus, Springer and others.

Leave a Reply

Your email address will not be published. Required fields are marked *