15. Exception Handling – Object-Oriented Programming with ANSI and Turbo C++

15

CHAPTER

Exception Handling

C
H
A
P
T
E
R

O
U
T
L
I
N
E
—•  15.1 Introduction
—•  15.2 Principles of Exception Handling
—•  15.3 The Keywords try, throw and catch
—•  15.4 Exception Handling Mechanism
—•  15.5 Multiple Catch Statements
—•  15.6 Catching Multiple Exceptions
—•  15.7 Rethrowing Exception
—•  15.8 Specifying Exception
—•  15.9 Exceptions in Constructors and Destructors
—•15.10 Controlling Uncaught Exceptions
—•15.11 Exception and Operator Overloading
—•15.12 Exception and Inheritance
—•15.13 Class Template with Exception Handling
—•15.14 Guidelines for Exception Handling

15.1 INTRODUCTION

While writing large programs, a programmer makes many mistakes. Due to this, bugs occur even in the released softwares. Developing an error free program is the objective and intention of the programmer. Programmers have to take care to prevent errors. Errors can be trapped using exception-handling features.

Few languages support exception-handling features. Without this feature, the programmers have to find out errors himself/ herself. The errors may be logical errors or syntactic mistakes (syntax mistakes). The logical errors remain in the program due to poor understanding of the program. The syntax mistakes are due to lack of understanding of the programming language. C++ provides exception-handling procedure to reduce the errors that a programmer makes.

The programmer always faces unusual errors while writing programs. An exception is an abnormal termination of a program, which is executed in a program at run-time or it may be called at runtime when an error occurs. The exception contains warning messages like invalid argument, insufficient memory, division by zero, and so on. ANSI C++ has built in language functions for trapping the errors and control the exceptions. All C++ compilers support this newly added facility.

15.2 PRINCIPLES OF EXCEPTION HANDLING

Like errors, exceptions are also of two types. They are as follows:

(a) Synchronous exceptions

(b) Asynchronous exceptions

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 action. The routine needs to carry following responsibilities:

(1) Detect the problem

(2) Warn that an error has come

(3) Accept the error message

(4) Perform accurate actions without troubling the user

An exception is an object. It is sent from the part of the program where an error occurs to that part of the program which is going to control the error. Exception provides an explicit pathway that contains errors to the code that controls the errors.

15.3 THE KEYWORDS try, throw AND catch

Exception handling technique passes control of 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 throw statement.

(1) The Keyword try

The try keyword is followed by a series of statements enclosed in curly braces.

Syntax of try statement
try 
{ 
  statement 1; 
  statement 2;
}

(2) The Keyword throw

The function of throw statement is to send the exception found. The declaration of throw statement is as given below:

Syntax of throw statement
throw (excep);
throw excep;
throw // re-throwing of an exception

The argument excep is allowed in any type and it may be a constant. The catch block associated with try block catches the exception thrown. The control is transferred from try block to catch block. The throw statement can be placed in function or in nested loop but it should be in try block. After throwing exception, control passes to the catch statement.

(3) The Keyword catch

Like try block, catch block also contains a series of statements enclosed in curly braces. It also contains an argument of exception type in parenthesis.

Syntax of catch statement
try 
{
  Statement 1; 
  Statement 2;
}
  catch ( argument)
{
  statement 3; // Action to be taken
}

When exception is found the catch block is executed. The catch( ) statement contains an argument of exception type and it is optional. When argument is declared it can be used in the catch block. After 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 mismatch is found the program terminates.

15.4 EXCEPTION HANDLING MECHANISM

C++ exception handling mechanism provides three keywords; try, throw, and catch. The keyword try is used at the starting of exception. The throw block is present inside the try block. Immediately after try block, catch( ) block is present. Figure 15.1 shows 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 catch( ) block that an error has occurred in the try block statement. Only errors occurring inside the try block are used to throw exception. The catch block receives the exception send by the throw block. The general form of the statement is shown in Figure 15.2.

When try block passes an exception using throw statement, the control of the program passes to the catch block. The data types used by throw and catch statements must be the same otherwise program gets aborted using abort( ) function, that is executed implicitly by the compiler. When no error is found and no exception is thrown, in such a situation catch block is disregarded and the statement after the catch block is executed.

Fig. 15.1 Exception mechanism

Fig. 15.2 try, throw, and catch blocks

15.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 <<"\n Enter values of x and y\n";
  cin>>x>>y; 
  int j; 
  j=x>y ? 0 :1; 

try 
{ 
    if (j==0) 
  {    cout <<"Subtraction (x-y)= "<<x-y<<"\n";    }

  else {  throw(j);  }
}
 
catch (int k) 
{ 
cout <<"Exception caught : j = "<<j <<"\n";
} 
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, values of x and y are entered. The conditional operator tests the two numbers. If x is greater than y then zero is assigned to j, otherwise 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.

15.5 MULTIPLE CATCH STATEMENTS

We can also define multiple catch blocks, in try blocks. Such program also contain multiple throw statements based on certain conditions. The format of multiple catch statement is given below:

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 appropriate by 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 terminates. In multiple catch ( ) statement, if objects of many catch statements are similar to type of an exception, in such a situation the first catch ( ) block that matches is executed.

15.2 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
      if (k>0) throw ‘P’; 
      else
      if (k<0) throw .0;
      cout <<"*** try block ***\n";
  }
catch(char g)
{
    cout <<"Caught a positive value \n";
} 

catch (int j)
{
    cout <<"caught a null value \n";
}

catch (double f)
{
    cout <<"Caught a negative value \n";
} 

cout <<"*** try catch ***\n \n"; 
}

int main( )
{
cout <<"Demo of multiple catches\n";
num(0);
num(5);
num(-l);

return 0; 
}

OUTPUT

Demo of multiple catches
caught a null value
*** try catch ***

Caught a positive value
*** try catch ***

Caught a negative value
*** try catch ***

Explanation: In the above program, function num( ) contains try block with multiple catch blocks. In function main( ), the user-defined function num( ) is invoked with one argument. The if statement within the try block checks the number whether it is positive, negative or zero. According to this, exception is thrown and respective catch( ) block is executed. Here, in throw statement, objects of different data types such as int, char and double are used to avoid ambiguity.

15.6 CATCHING MULTIPLE EXCEPTIONS

It is also possible to define single or default catch( ) block from one or more exceptions of different types. In such a situation, a single catch block is used for catch exceptions thrown by multiple throw statements.

catch( ) 
{
  // statements for handling 
  // all exceptions
}

15.3 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 ***\n";
  }

catch (...) 
{
  cout <<"\n Caught an exception\n";
}

}
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 same as the previous one. Here, only one difference is observed and that is, instead of multiple catch blocks, 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 thrown exceptions.

15.7 RETHROWING EXCEPTION

It is also possible to pass again the exception received to another exception handler i.e., an exception is thrown from catch( ) block and this is known as rethrowing of 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.

15.4 Write a program to rethrow an exception.

# include <iostream.h>
void sub( int  j, int k)
{
     cout <<"inside function sub ( )\n";
     try
     {
        if (j==0)
            throw j;
        else

            cout <<"Subtraction = "<<j-k <<"\n";
     }
     catch (int)
     {
        cout <<"Caught null value \n";
        throw;
     }
     cout <<"** End of sub ( ) ***\n\n";
}


int main( )
{
cout <<"\n inside function main ( )\n";
try
{
sub (8,5);
sub (0,8);
}
catch (int)
{
     cout <<"caught null inside main ( ) \n";
}
cout <<"end of function main ( ) \n";


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 function sub( ) and other in function main( ). The sub( ) function has two integer arguments. When sub( ) function is invoked two integer values are sent to this function. The if statement in try block of sub( ) function checks whether the value of first variable i.e., 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 statement throw. Here, throw statement is used without any argument. The catch block of function main catches the rethrown exception.

15.8 SPECIFYING EXCEPTION

The specified exceptions are used when we want to bind the function to throw only specified exception. Using a throw list condition can do this. The format for such exception is given below.

Specifying Exceptions
data-type function_name (parameter list) throw (data type list) 
{
  Statement 1;
  Statement 2; Function definition 
  Statement 3;
}

The data type list indicates the type of exceptions to be thrown. If we want to deny a function from throwing exception, we can do this by declaring data type list void as per the following statement.

throw ( );   //   void or vacant list

15.5 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 <<"\n End of function check ( )";
}
void  main ( )
{
     try {
        cout <<"k==1\n";

        check(1);

        cout <<"k==2\n";
        check(2);


        cout <<"k==-2\n";
        check(-2);


        cout <<"k==3\n";
        check(3);
     }
     catch ( char g)
     {
        cout <<"Caught a character exception \n";
     }
     catch (int j)
     {
        cout <<"Caught a character exception \n";
     }
     catch (double s)
     {
        cout <<"Caught a double exception \n";
     }


     cout <<"\n End of main ( ) ";
}

OUTPUT
k==1
Caught a character exception

End of main ( ) Press any k

Explanation: In the above program, check( ) function is defined. It is followed by exception, specifying statement. The if statements check the value of formal argument. According to the value, exception is thrown. In function main( ), the function check( ) is invoked with different values. The output of the program is above.

15.9 EXCEPTIONS IN CONSTRUCTORS AND DESTRUCTORS

Copy constructor is called in exception handling when an exception is thrown from the try block using throw statement. Copy constructor mechanism is applied to initialize the temporary object. In addition, destructors are also executed to destroy the object. If exception is thrown from constructor, destructors are called only completely constructed objects.

15.6 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<<"\n In destructor";
       }
       void  operator ++ (int)  //  postfix notation
       {  x++;  }

       void operator -- ( )  // prefix notation
       {
            --x; }
       void show ( )
       {
            cout <<"\n x="<<x;
       }
};


number :: number ( float k)
       {
            if (k==0)
                throw number( );
            else
            x=k;
  }


void main( )
{
       try
{

       number N(2.4);
       cout <<"\n Before incrimination: ";
       N.show ( );
       cout <<"\n After incrimination: ";
       N++;   // postfix increment
       N.show( );
       cout <<"\n After decrementation:";
       --N;   // prefix decrement
       N.show( );
       number N1(0);
}


catch (number)
{


       cout <<"\n invalid number";
       exit(1);
}
}

OUTPUT

Before incrimination:
x=2.4

After incrimination:
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 data member x with the value given by the user. The overloaded operators are used to increase and decrease the value of 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 throw when object N1 is created. When exception is thrown control goes to catch( ) block. The catch( ) block terminates the program. The destructors are also invoked.

15.10 CONTROLLING UNCAUGHT EXCEPTIONS

C++ has the following functions to control uncaught exceptions.

(1) The terminate( ) Function

In case exception handler is not defined when exception is thrown terminate( ) function is invoked. Implicitly the abort( ) function is invoked.

15.7 Write a program to catch uncaught exceptions.


# include <iostream.h>
class one {};
class two {};


void main( )
{


     try
     {
       cout <<" An uncaught exception\n";
       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 exception for class one and it 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, abort( ) function is called implicitly by the compiler.

(2) The set_terminate( ) Function

The set_terminate( ) function is used to transfer the control to specified error handling function. The set_terminate( ) function requires only one argument that 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.

15.8 Write a program to demonstrate the use of set_terminate( ) function.

# include <iostream.h>
# include <except.h>


class one {};
class two {};


void  skip( )
{


     cout <<"\n function skip ( ) is invoked";
}


void main( )
{


     set_terminate(skip);


     try
     {
       cout<<"\n Throwing exception : ";
       throw (two);
     }


     catch (one)
     {
       cout <<"\n An exception of one is caught";
     }
     // At this point function skip is invoked

OUTPUT

Throwing exception
function skip ( ) is invoked

Explanation: This program is same as the last one. The only difference is that compiler does not find 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 compiler does not find a matching exception instead of terminating program, it invokes the function associated with set_terminate( ) function. Here, the exception is thrown for 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.

15.11 EXCEPTION AND OPERATOR OVERLOADING

Exception handling can be used with operator-overloaded functions. The following program illustrates the same.

15.9 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 <<"\n 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 <<"\n Before decrementation: "; 
    N.show ( );


    while (1) 
    {
    cout <<"\n After decrementation"; 
    --N;
    N.show( ); 
    }
}
catch (number) 
{
    cout <<"\n Reached to zero"; 
    exit(1);
}
 
}

OUTPUT

Before decrementation
x=4

After decrementation
x=3

After decrementation
x=2

After decrementation
x=1

After decrementation
x=0

After decrementation
Reached to zero

Explanation: In this program, the operator -- is overloaded. This operator when used with class objects decreases the values of class members. Using while( ) loop the value of object N is continuously decreased. The object N is initialized with four. The operator --( ) function checks the value of x (member of object N) and if value of x reaches to zero, an exception is thrown which is caught by the catch( ) statement.

15.12 EXCEPTION AND INHERITANCE

In the last few examples, we learned how exception mechanism works with operator function and with constructors and destructors. The following program explains how exception handling can be done in inheritance.

15.10 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 <<"\n Enter Name and Age : "; 
      cin >>name>>age;

      if (age<=0) 
      throw abc( );

      cout <<"\n Enter Height and Weight : "; 
      cin >>height >>weight;
    }

void show( ) 
{
  cout <<"\n Name : "<<name <<"\n Age : "<<age<<" Years"; 
 cout <<"\n Height : "<<height <<" Feets"<<"\n Weight : " <<weight <<" Kg.";
}
};
void main( ) 
{
    try 
    {

      abc x;
      x.getdata( );  // Reads data through keyboard
      x.show( );     // Displays data on the screen

    }
  catch (abc) { cout <<"\n 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 function main( ), x is an object of 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.

15.13 CLASS TEMPLATE WITH EXCEPTION HANDLING

The following program illustrates how excepting handling can be implemented with class templates.

15.11 Write a program to show exception handling with class template.

# include <iostream.h>
# include <math.h>

class sq{};

template <class T>
class square 
{
    T s; 

public:

    square ( T x) 

    {
       sizeof(x)==1 ? throw sq ( ) : s=x*x;
    }

    void show( )
    {

       cout <<"\n Square : "<<s;
    }
};

void main( ) 
{

    try 
    {

      square <int> i(2); 
      i.show( );
      square <char> c(’C'); 
      c.show( );

    }

    catch (sq) 
    {
       cout <<"\n Square of character cannot be calculated";
    }
}

OUTPUT

Square: 4

Square of character cannot be calculated

Explanation: In the above program, the class square uses template type of argument. Using conditional operator, size of passed argument is checked. If it is equal to one an exception is thrown, otherwise square is calculated and stored in the class data member s. The show( ) function displays the square on the screen. When a character type data is entered, an exception is thrown because size of character is one and square cannot be calculated.

15.14 GUIDELINES FOR EXCEPTION HANDLING

(1) It is not essential for throw statement to appear in the try block in order to throw an exception. The throw statement can be placed in any function, if the function is to be invoked through the try block.

Fig. 15.3 throw statement out of try block

As shown in the Figure 15.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 above style.

(2) When an exception not specified is thrown, it is known as unexpected exception.

(3) In case an exception is thrown before complete execution of constructor, destructor for that object will not be executed.

(4) As soon as an exception is thrown, the compiler searches nearby handlers (catch blocks). After finding a match, it will be executed.

(5) Overuse of exception handling increases the program size. So apply it whenever most necessary. Incorrect use of exception handling is not consistent and generates bugs in the program. Such bugs are hard to debug.

SUMMARY

(1) There are a few languages that support exception handling feature. Without this feature, the programmer will have to detect bugs.

(2) The errors may be logical errors or syntactic mistakes (syntax mistakes). The logical errors remain in the program due to unsatisfactory understanding of the program. The syntax mistakes are due to lack of understanding of the programming language itself.

(3) ANSI C++ has built in language functions for trapping the errors and controlling the exceptions. All C++ compilers support this newly added facility.

(4) C++ provides a type-secure, integrated procedure for coping with the predictable but peculiar conditions that arise at run-time.

(5) The goal of exception handling is to create a routine that detects and sends an exceptional condition in order to execute suitable action.

(6) An exception is an object. It is send from the part of the program where an error occurs to the part of the program which is going to control the error.

(7) C++ exception method provides three keywords, try, throw, and catch. The keyword try is used at the starting of exception. The entire exception statements are enclosed in the curly braces. It is known as try block.

(8) The catch block receives the exception send by the throw block in the try block.

(9) We can also define multiple catch blocks in try block, such a program also contains multiple throw statements based on certain conditions.

(10) It is also possible to define single or default catch( ) block from one or more exception of different types. In such a situation, a single catch block is used for catch exceptions thrown by the multiple throw statements.

(11) It is also possible to again pass the exception received to another exception handler i.e., an exception is thrown from catch( ) block and this is known as rethrowing of exception.

(12) The specified exceptions are used when we want to bind the function to throw only specified exceptions. Using a throw list condition can also do this.

EXERCISES

[A] Answer the following questions.

(1) What do you mean by exception handling?

(2) How many different types of errors are encountered in a program?

(3) Describe the role of keywords try, catch, and throw in exception handling?

(4) What will happen if the programming language does not support the exception handling feature?

(5) What do you mean by re-throwing of an exception?

(6) Explain specifying exception with necessary steps.

(7) How are multiple catch blocks defined?

(8) What will happen if an exception is thrown for which no matching catch( ) block is defined?

(9) Explain guidelines for exception handling.

(10) Explain mechanism of exception handling.

(11) Explain the use of function set_terminate ( ). How can we associate a function with this statement?

[B] Answer the following by selecting the appropriate option.

(1) The statement catches the exception

(a) catch

(b) try

(c) throw

(d) template

(2) In multiple catch( ) statement the number of throw statements are

(a) same as catch( ) statement

(b) twice than catch( ) statement

(c) only one throw statement

(d) none of the above

(3) Exception is generated in

(a) try block

(b) catch block

(c) throw block

(d) none of the above

(4) In exception handling one of the following functions is implicitly invoked

(a) abort( )

(b) exit( )

(c) assert( )

(d) none of the above

(5) What will happen if throw( ) function has an empty exception and is placed after a function argument list

(a) no exception will be thrown

(b) default exception will be invoked

(c) the nearest one exception is thrown

(d) unexpected actions by the program

(6) If catch( ) statement is defined to catch exception for base class type object it can also catch all______ derived class of the base class

(a) errors

(b) parameters

(c) exceptions for objects

(d) none of the above

[C] Attempt the following programs.

(1) Write a program to accept 10 integers in an array. Check all numbers in the array. When any negative number is found, throw an exception.

(2) Write a program to accept a string. When any space is encountered, throw exception.

(3) Write a program to explain the concept of multiple catch statements.

(4) Write a program to use catch( ) statement.

(5) Write a program to call a nested function. The function has an exception. Include essential exception handling statements.