19.2 Principles of Exception Handling
19.3 The Keywords try, throw, and catch
19.4 Guidelines for Exception Handling
19.5 Multiple catch Statements
19.6 Catching Multiple Exceptions
19.9 Exceptions in Constructors and Destructors
19.10 Controlling Uncaught Exceptions
19.11 Exceptions and Operator Overloading
19.12 Exceptions and Inheritance
19.13 Class Templates with Exception Handling
While writing large programs, a programmer usually makes many mistakes. Due to this, bugs occur even in the released softwares. Developing an error-free program is the only objective and intention of the programmer. Programmers should take care to prevent errors. Errors can be trapped using exception-handling features.
A few languages support exception-handling features. Without this feature, the programmers should find out errors on their own. The errors may be logical errors or syntactic mistakes (syntax mistakes). The logical error remains in the program due to a poor understanding of the program. The syntax mistakes made are due to a lack of understanding of the programming language. C++ provides an exception-handling procedure to reduce the errors that the programmer makes.
The programmer always faces unusual errors while writing programs. An exception is an abnormal termination of the program, which is executed in a program at run time or it may be called at run time when the error occurs. The exception contains warning messages such as invalid argument, insufficient memory, and division by zero. ANSI C++ is built in language functions for trapping errors and controlling exceptions. All C++ compilers support this newly added facility.
Similar to errors, exceptions are also of two types. They are as follows:
C++ has a well-organized, object-oriented method to control run-time errors that occur in the program. The goal of exception handling is to create a routine that detects and sends an exceptional condition in order to execute suitable actions. The routine needs to carry out the following responsibilities:
An exception is an object. It is sent from the part of the program where an error occurs to the part of the program that is going to control the error. An exception provides an explicit pathway that contains errors to the code which controls these errors.
The exception-handling technique passes the control of a program from a location of exception in a program to an exception-handler routine linked with the try block. An exception-handler routine can only be called by the throw statement.
Syntax of try statement
try
{
statement 1;
statement 2;
}
The argument excep is allowed to be of any type, and it may be a constant. The catch block associated with the try block catches the exception thrown. The control is transferred from the try block to the catch block. The throw statement can be placed in a function or is a nested loop, but it should be in the try block. After throwing the exception, control passes to the catch statement.
Syntax of catch statement
try
{
Statement 1;
Statement 2;
}
catch ( argument)
{
statement 3; // Action to be taken
}
When an exception is found, the catch block is executed. The catch statement contains an argument of exception type, and it is optional. When an argument is declared, the argument can be used in the catch block. After the execution of the catch block, the statements inside the blocks are executed. In case no exception is caught, the catch block is ignored, and if a mismatch is found, the program is terminated.
The C++ exception-handling mechanism provides three keywords; they are try, throw, and catch. The keyword try is used at the starting of the exception. The throw block is present inside the try block. Immediately after the try block, the catch block is present. Figure 19.1 shows the try, catch, and throw statements.
As soon as an exception is found, the throw statement inside the try block throws an exception (a message for the catch block that an error has occurred in the try block statements). Only errors occurring inside the try block are used to throw exceptions. The catch block receives the exception that is sent by the throw block. The general form of the statement is as per Figure 19.2.
When the try block passes an exception using the throw statement, the control of the program passes to the catch block. The data type used by throw and catch statements should be same; otherwise, the program is aborted using the abort() function, which is executed implicitly by the compiler. When no error is found and no exception is thrown, in such a situation, the catch block is disregarded, and the statement after the catch block is executed.
Fig. 19.1 Exception mechanism
Fig. 19.2 try, throw, and catch blocks
19.1 Write a program to throw exception when j=1 otherwise perform the subtraction of x and y.
#include<iostream.h>
#include<conio.h>
int main()
{
int x,y;
cout<<“ Enter values of x and y ”;
cin>>x>>y;
int j;
j=x>y ? 0 :1;
try
{
if (j==0)
{ cout<<“Subtraction (x-y)=”<<x-y<<“ ”; }
else { throw(j); }
}
catch (int k)
{
cout<<“Exception caught : j =”<<j <<“ ”;
}
return 0;
}
}
OUTPUT
Enter values of x and y
7 8
Exception caught : j = 1
Enter values of x and y
4 8
Exception caught : j = 1
Explanation: In the above program, the values of x and y are entered. The conditional operator tests the two numbers; if x is greater than y, zero is assigned to j; otherwise, it is one. In the try block, the if condition checks the value of j; the subtraction is carried out when j is zero; otherwise, the else block throws the exception. The catch statement catches the exception thrown. The output of the program is shown above.
19.2 Write a program to define function that generates exception.
#include<iostream.h>
void sqr()
{
int s;
cout<<“ Enter a number:”;
cin>>s;
if (s>0)
{
cout<<“Square=”<<s*s;
}
else
{
throw (s);
}
}
int main()
{
try
{
sqr();
sqr();
}
catch (int j)
{
cout<<“ Caught the exception ”;
}
return 0;
}
OUTPUT
Enter a number : 5
Square = 25
Enter a number : 0
Caught the exception
Explanation: In the above program, the function sqr() is defined. The function sqr() reads an integer through the keyboard and displays its square. Before calculating the square, the if statement checks the number. If it is greater than zero, then the if block calculates the square and displays it; otherwise, the else block throws the exception. In the function main(), in the try block, the function is called twice. In case an exception is thrown from the function sqr(), the catch statement catches it, and the catch block is executed. This happens only when the user enters the number 0 or less than zero. If the user enters 0 in the first call, then the exception is thrown, and the catch block is executed. The compiler ignores the next statement of the try block. Once the control skips from the try block, it never comes back to execute the remaining statements. Thus, in this program if in the first call the user enters 0, then the second call of the function sqr() is not taken into account.
We can also define multiple catch blocks; in the try block, such programs also contain multiple throw statements based on certain conditions. The format of multiple catch statements is as follows:
try
{
// try section
}
catch (object1)
{
// catch section1
}
catch (object2)
{
// catch section2
}
. . . . . . .
. . . . . . .
catch (type n object)
{
// catch section-n
}
As soon as an exception is thrown, the compiler searches for an appropriate matching catch block. The matching catch block is executed, and control passes to the successive statement after the last catch block. In case no match is found, the program is terminated. In a multiple catch statement, if objects of many catch statements are similar to the type of an exception, in such a situation, the first catch block that matches is executed.
19.3 Write a program to throw multiple exceptions and define multiple catch statement.
#include<iostream.h>
void num (int k)
{
try
{
if (k==0) throw k;
else
else
if (k<0) throw .0;
cout<<“*** try block *** ”;
}
catch(char g)
{
cout<<“Caught a positive value ”;
}
catch (int j)
{
cout<<“caught an null value ”;
}
catch (double f)
{
cout<<“Caught a Negative value ”;
}
cout<<“*** try catch *** ”;
}
int main()
{
cout<<“Demo of Multiple catches ”;
num(0);
num(5);
num(-1);
return 0;
}
OUTPUT
Demo of Multiple catches
caught an null value
*** try catch ***
Caught a positive value
*** try catch ***
Caught a Negative value
*** try catch ***
Explanation: In the above program, the function num() contains the try block with multiple catch blocks. In the function main(), the user-defined function num() is invoked with one argument. The if statement within the try block checks the number to see whether it is positive, negative, or zero. According to this, an exception is thrown, and the respective catch block is executed. Here, in the throw statement, objects of different data types such as int, char, and double are used to avoid ambiguity.
It is also possible to define a single or default catch block from one or more exceptions of different types. In such a situation, a single catch block is used to catch the exceptions thrown by the multiple throw statements.
catch
{
// Statements for handling
// all exceptions
}
19.4 Write a program to catch multiple exceptions.
#include<iostream.h>
void num (int k)
{
try
{
if (k==0) throw k;
else
if (k>0) throw ‘P’;
else
if (k<0) throw .0;
cout<<“*** try block *** ”;
}
catch
{
cout<<“ Caught an exception ”;
}
}
int main()
{
num(0);
num(5);
num(-1);
return 0;
}
OUTPUT
Caught an exception
Caught an exception
Caught an exception
Explanation: The above program is similar to the previous one. Here, only one difference is observed and that is, instead of multiple catch blocks, a single catch block is defined. For all the exceptions thrown, the same catch block is executed. It is a generic type of catch block. The statement catch catches all the exceptions thrown.
It is also possible to again pass the exception received to another exception handler; that is, an exception is thrown from the catch block; this is known as the re-throwing exception. The following statement accomplishes this:
throw;
The above throw statement is used without any argument. This statement throws the exception caught to the next try catch statement. The following program illustrates this:
19.5 Write a program to re-throw an exception.
#include<iostream.h>
void sub( int j, int k)
{
cout<<“inside function sub() ”;
try
{
if (j==0)
throw j;
else
cout<<“Subtraction=”<<j-k<<“ ”;
}
catch (int)
{
cout<<“Caught Null value ”;
throw;
}
cout<<“** End of sub() *** ”;
}
int main()
{
cout<<“ inside function main() ”;
try
sub (8,5);
sub (0,8);
}
catch (int)
{
cout<<“caught null inside main() ”;
}
cout<<“end of function main() ”;
return 0;
}
OUTPUT
inside function main()
inside function sub()
Subtraction = 3
** End of sub() ***
inside function sub()
Caught Null value
caught null inside main()
end of function main()
Explanation: In the above program, two try blocks are defined. One is defined in the function sub(), and the other is defined in the function main(). The sub() function has two integer arguments. When the sub() function is invoked, two integer values are sent to this function. The if statement in the try block of the sub() function checks whether the value of the first variable, that is, j is zero or non-zero. If it is non-zero, subtraction is carried out; otherwise, the throw statement throws an exception. The catch block inside the function sub() collects this exception and again throws the exception using the throw statement. Here, the throw statement is used without any argument. The catch block of the main function catches the re-thrown exception.
The specified exceptions are used when we want to bind the function to throw only specified exceptions. Specific exception is thrown using condition statement and list of data items in throw. The format for such exceptions is as given below:
Specifying Exceptions
Data-type fucntion_name (parameter list) throw (data type list)
{
Statement 1;
Statement 2; Function definition
statement 3;
}
The data type list indicates the type of exception that is permitted to be thrown. If we want to deny a function from throwing an exception, declaring the data type list void as per the following statement can do this.
throw(); // void or vacant list
19.6 Write a program to restrict a function to throw only specified type of exceptions.
#include<iostream>
using namespace std;
void check (int k) throw (int,double)
{
if (k==1) throw ‘k’;
else
if (k==2) throw k;
else
if (k==-2) throw 1.0;
cout<<“ End of function check()”;
}
void main()
{
try {
cout<<“k==1 ”;
check(1);
cout<<“k==2 ”;
check(2);
cout<<“k==-2 ”;
check(-2);
cout<<“k==3 ”;
check(3);
}
catch ( char g)
{
cout<<“Caught a character exception ”;
}
catch (int j)
{
cout<<“Caught a character exception ”;
}
catch (double s)
{
cout<<“Caught a double exception ”;
}
cout<<“ End of main()”;
}
OUTPUT
k==1
Caught a character exception
End of main() Press any k
Explanation: In the above program, the check() function is defined. It is followed by an exception specifying statement. The if statements check the value of the formal argument. According to the value, an exception is thrown. In function main(), the function check() is invoked with different values. The output of the program is as given above.
A copy constructor is called in exception handling when an exception is thrown fro the try block using the throw statement. The copy constructor mechanism is applied to initialize the temporary object. In addition, destructors are also executed to destroy the object. If an exception is thrown from the constructor, destructors are called only for those objects that are completely constructed.
19.7 Write a program to use exception handling with constructor and destructor.
#include<iostream.h>
#include<process.h>
class number
{
float x;
public :
number (float);
number() {};
~number()
{
cout<<“ In destructor”;
}
void operator ++ (int) // postfix notation
{ x++; }
void operator --() // prefix notation
{
--x; }
void show()
{
cout<<“ x=”<<x;
}
};
number :: number ( float k)
{
if (k==0)
throw number();
else
x=k;
void main()
{
try
{
number N(2.4);
cout<<“ Before Increasing:”;
N.show();
cout<<“ After Increasing:”;
N++; // postfix increment
N.show();
cout<<“ After Decrementation:”;
--N; // prefix decrement
N.show();
number N1(0);
}
catch (number)
{
cout<<“ invalid number”;
exit(1);
}
}
OUTPUT
Before Increasing:
x=2.4
After Increasing:
x=3.4
After Decrementation:
x=2.4
In destructor
In destructor
invalid number
Explanation: In the above program, the operators ++ and – are overloaded. The class number() has two constructors and one destructor. The one-argument constructor is used to initialize the data member x with the value given by the user. The overloaded operators are used to increase and decrease the value of the object. When the user specifies the zero value, an exception is thrown from the constructor. The exception is caught by the catch statement. In function() main(), two objects N and N1 are declared. The exception is thrown when the object N1 is created. When the exception is thrown, the control goes catch block. The catch block terminates the program. The destructors are also invoked.
C++ has the following functions, and these can be used to control uncaught exceptions.
terminate(): In case the exception handler is not defined when an exception is thrown, in such a case, the terminate() function is invoked. Implicitly, the abort() function is invoked.
19.8 Write a program caught uncaught exceptions.
#include<iostream.h>
class one {};
class two {};
void main()
{
try
{
cout<<“An Uncaught exception ”;
throw two();
}
catch (one)
{
cout<<“Exception for one”;
}
}
Explanation: In the above program, an exception is thrown for class two using the statement throw two(). The catch block is defined to handle the exception for class one, and the catch block contains an argument of class one type. When an exception is thrown, it does not find a match; hence, the program is terminated. For termination, the abort() function is called implicitly by the compiler.
set_terminate()
The set terminate() function is used to transfer the control to the specified error-handling function. The set_terminate() function requires only one argument, which is nothing but a function name where control is transferred. It returns nothing. When no function is specified, the program is terminated by an implicit call to abort() function.
19.9 Write a program to demonstrate the use of set_terminate() function.
#include<iostream.h>
#include<except.h>
class one {};
class two {};
void skip()
cout<<“ function skip() is invoked”;
}
void main()
{
set_terminate(skip);
try
{
cout<<“ Throwing exception:”;
throw (two);
}
catch (one)
{
cout<<“ An exception of one is caught”;
}
}
// At this point function skip is invoked
OUTPUT
Throwing exception
function skip() is invoked
Explanation: This program is similar to the previous one. The only difference is that in the previous program the compiler does not found a matching catch statement for the exception thrown by the throw statement. The program is terminated. In this program, at the beginning, a user-defined function skip() is defined. The skip() function is associated with the set_terminate() function. When a compiler does not found a matching exception instead of terminating a program, it invokes the function associated with the set_terminate() function. Here, the exception is thrown for an object of class two. The catch statement holds an object of class one. Hence, the thrown exception object does not match the catch object. Due to this mismatch, the function skip() is invoked to handle such an uncertain situation.
An exception handling can be sued with operator-overloaded functions. The following program illustrates the same:
19.10 Write a program to throw exception from overloaded operator function.
#include<iostream.h>
#include<process.h>
class number
int x;
public :
number() {};
void operator --();
void show() { cout<<“ x=”<<x; }
number ( int k) { x=k; }
};
void number :: operator --() // prefix notation
{
if (x==0) throw number();
else --x;
}
void main()
{
try
{
number N(4);
cout<<“ Before Decrementation:”;
N.show();
while (1)
{
cout<<“ After Decrementation”;
--N;
N.show();
}
}
catch (number)
{
cout<<“ Reached to zero”;
exit(1);
}
}
OUTPUT
Before Decrementation
x=4
After Decrementation
x=3
After Decrementation
x=2
After Decrementation
After Decrementation
x=0
After Decrementation
Reached to zero
Explanation: In this program, the operator – is overloaded. When used with class objects, this operator decreases the values of class members. Using the while() loop, the value of the object N is continuously decreased. The object N is initialized with four. The operator – () function checks the value of x (member of object N); if the value of x reaches zero, an exception is thrown, which is caught by the catch statement.
In the last few examples, we have learned how the exception mechanism works with the operator function and with constructors and destructors. The following program explains how exception handling can be done with inheritance:
19.11 Write a program to throw an exception in derived class.
#include<iostream.h>
class ABC
{
protected:
char name[15];
int age;
};
class abc : public ABC // public derivation
{
float height;
float weight;
public:
void getdata()
{
cout<<“ Enter Name and Age:”;
cin>>name>>age;
if (age<=0)
throw abc();
cout<<“ Enter Height and Weight:”;
cin>>height >>weight;
}
void show()
cout<<“ Name:”<<name<<“ Age:”<<age<<“ Years”;
cout<<“ Height:”<<height<<“Feets”<<“ Weight:” <<weight<<“Kg.”;
}
};
void main()
{
try
{
abc x;
x.getdata(); // Reads data through keyboard.
x.show(); // Displays data on the screen.
}
catch (abc) { cout<<“ Wrong age”;}
}
OUTPUT
Enter Name and Age: Amit 0
Wrong age
Explanation: In the above program, the two classes ABC and abc are declared. The class ABC has two protected data members name and age. The class abc has two float data members’ height and weight with two member functions getdata() and show(). The class abc is derived from class ABC. The statement class abc: public ABC defines the derived class abc. In the function main(), x is an object of the derived class abc. The object x invokes the member function getdata() and show(). This function reads and displays data, respectively. In the function getdata(), the if statement checks the age entered. If the age entered is zero or less than zero, an exception is thrown. The catch block is executed, and the message “Wrong age” is displayed.
The following program illustrates how excepting handling can be implemented with class templates:
19.12 Write a program to show exception handling with class template.
#include<iostream.h>
#include<math.h>
class sq {};
template <class T>
class square
{
public:
square ( T x)
{
sizeof(x)==1 ? throw sq() : s=x*x;
}
void show()
{
cout<<“ Square:”<<s;
}
};
void main()
{
try
{
square <int> i(2);
i.show();
square <char> c(‘C’);
c.show();
}
catch (sq)
{
cout<<“ Square of character cannot be calculated”;
}
}
OUTPUT
Square: 4
Square of character cannot be calculated
Explanation: In the above program, the class square uses the template type of argument. Using conditional operators, the size of the passed argument is checked. If it is equal to one, an exception is thrown; otherwise, the square is calculated and stored in the class data member s. The show() function displays the square on the screen. When character-type data are entered, an exception is thrown, because the size of the character is one and the square cannot be calculated.
|
Show() |
|
|
{ |
{ |
|
statement; |
statement; |
|
show (variable) |
throw (object); |
|
statement; |
} |
|
} |
|
|
catch (object) |
|
|
{ |
|
|
statement; |
|
|
} |
Fig. 19.3 throw statement out of try block
As shown in Figure 19.3, the throw statement is present in the show() function. The show() function is invoked inside the try block. Thus, exception handling can also be defined in the manner described above.
19.13 Write a program to enter five numbers in an integer array. Display the largest number. If the array contains null element, throw the exception.
#include<iostream.h>
int main()
{
int max[5],k=0,m;
cout<<“ Enter five numbers:”;
for (k=0;k<5;k++)
cin>>max[k];
try
{
for (k=0;k<5;k++)
{
if (max[k]==0)
if (max[k]>m)
m=max[k];
}
cout<<“Largest number is :”<<m;
}
catch (int k)
{
cout<<“ caught a null value”;
}
}
OUTPUT
Enter five numbers : 4 5 8 7 0
caught a null value
Explanation: In the above program, an integer array max [5] is declared. The cin statement within the first for loop reads integers through the keyboard. The second for loop and the second if statement within it checks the successive numbers of arrays and stores the largest number in the variable m. Before this, the first if statement checks whether the number is zero. If the number is zero, an exception is thrown.
19.14 Write a program to enter a string and display it and throw an exception when null character is detected.
#include<iostream.h>
int main()
{ char text[20];
int x=0;
cout<<“ Enter text:”;
cin.getline(text,20);
try
{
while (1)
{
if (text[x]==‘ ’)
throw text[x];
cout<<text[x];
x++;
}
}
catch (char c)
cout<<“ End of string”;
}
return 0;
}
OUTPUT
Enter text : Haste is Waste
Haste is Waste
End of string
Explanation: In the above program, a character array text [20] is declared. The cin statement accepts the string through the keyboard. The while loop and the statements within it are used to display the string. The if statement checks every character of the string to see whether it is a null character or other character. If it is a null character, an exception is thrown; otherwise, the character is displayed on the screen. Thus, at last when a null character is found, an exception is thrown. The message “End of string” is displayed by the catch block.
(A) Answer the following questions
(B) Answer the following by selecting the appropriate option
(c) Attempt the following programs