Advanced C++ - Part IV


The following topics are covered in this section:


Exception handling

Older C++ compilers will not support exception handling. This feature is used for dealing with certain specific situations (these situations are not supposed to occur and if you don’t provide some way of dealing with them then your program could simply freeze when the conditions really occur). To implement exception handling, C++ provides us with three keywords:

How do they work? First you try (or execute) the coding and in case some special situation is encountered, then the program will throw an exception. The exception that is thrown will be caught by the catch part of the program.

#include <iostream>
using namespace std;

int main( )
{
float a,b;
try
{
cout<<"\nEnter a number : ";
cin>>a;
cout<<"\nEnter the denominator : ";
cin>>b;
if (b= =0)
{
throw 0;
}
cout<<"\nResult of division : "<<a/b;
}

catch(int i)
{
cout<<"\nError - You entered : "<<i;
}
return 0;
}

The output if you enter two non-zero numbers will be:

Enter a number : 5
Enter the denominator : 4
Result of division : 1.25

Suppose the second number you enter is zero, the following will result:

Enter a number : 5
Enter the denominator : 0
Error - You entered : 0

You should note that once the program throws something, it will not execute what follows it within the try block. It will go directly to the catch block and execute the underlying statements. The catch block that you write should immediately follow after the try block. Even if you add one display statement between the try and catch blocks it will lead to errors. Can I have more than one catch? Yes but each catch should catch a different exception (meaning that the argument types for each one should be different). You can write one catch block to catch integers, one to catch strings etc. Suppose you want to catch everything that is thrown, there is a simple way to do it. Just use:

catch(…)
{
//body of the catch
}

The 3 consecutive dots imply that this ‘catch’ block will catch anything that is thrown.

Uncaught Exceptions

What will happen if we throw a string but we have programmed only for catching integers? This is what is called as an uncaught exception and if you try it out, your compiler will display the message:

    Abnormal Program Termination

Actually, the compiler executes the terminate ( ) function. The terminate ( ) function will in turn call the abort ( ) function. Usually, if there is some problem with the exception handling, then the compiler would either go to the terminate ( ) function or it would invoke the unexpected ( ) function. The unexpected ( ) function will call the terminate ( ) function. Hence, ultimately the program will call the abort ( ) function. You can create your own version of the terminate function (in other words, you can set the terminate function) using:

set_terminate(your-function);

For using this, you would need to make use of the <exception> header file.

#include <exception>
#include <iostream>
using namespace std;

void myterminate( )
{
cout<<"\nMy Terminate Function";
abort( );
}

int main( )
{ float a,b;
try
{
set_terminate(myterminate);
cout<<"\nEnter a number : ";
cin>>a;
cout<<"\nEnter the denominator : ";
cin>>b;

if (b= =0)
{
throw "zero";
}
cout<<"\nResult of division : "<<a/b;
}

catch(int i)
{
cout<<"\nError - You entered : "<<i;
}
return 0;
}

The output would be(when you enter the second number as 0):

Enter a number : 5
Enter the denominator : 0
My Terminate Function
Abnormal program termination

Thus you can see that the terminate ( ) function has been modified and even in our terminate ( ) function we make use of the abort( ) function. The idea is that you do not want the program execution to continue once the compiler encounters some problem in exception handling.

The <exception> also defines some standard exceptions that are thrown. For example:

bad_alloc - thrown if some problem is encountered using ‘new’
bad_exception
- thrown when exception doesn't match any catch

Just check out the following program:

#include <exception>
#include <iostream>
using namespace std;
int main( )
{
int *p;
try
{
    p = new int;
}

catch(bad_alloc)
{
cout<<"\nError in Allocation ";
return 1;
}
return 0;
}

Templates

This section is intended to provide a brief idea about templates rather than going too deep into the topic. Again this is a new feature incorporated in C++. First of all, you should know the reason behind the need for templates. Suppose you are writing a program in which you want to compare two numbers (finding out which one is greater or whether they are equal). Maybe in your program, once you want to compare integers and once you want to compare float quantities. As you know, you could write two separate functions to perform the task (of course you might in fact even feel that functions are not needed but let’s assume that you want to use functions). It seems odd that we’d have to write separate coding for integers and floating points (the process will be the same and only the data type is going to be different). Hence, instead of creating a specific function (for each data type), we can use a template function (or a generic function) to write a general function that would work with any data type.

The syntax for creating a template function would be as follows:

Template<class mytype> return-data function-name (parameters)
{
//body of function written using mytype as the data type
}

or

Template<class mytype>
return-data function-name (parameters)
{
//body of function written using mytype as the data type
}

To make it generic we have to write the entire function using mytype as the data type. What is mytype? Have a look at the example that follows. In this program we want to compare two numbers (a and b) and return 1 if a>b, return 0 if a=b and return –1 if a<b.

#include <iostream>
using namespace std;

template<class mytype>
int compare(mytype x,mytype y)
{
    if (x>y)
    {
        return 1;
    }
    else if (x<y)
    {
        return -1;
    }
    else if (x= =y)
    {
        return 0;
    }
}

int main( )
{
int a,b;
double i,j;

a=5;
b=10;
i=1.45;
j=1.35;

cout<<"\nComparing integers a and b the result is : "<<compare(a,b);
cout<<"\nComparing double i and j the result is : "<<compare(i,j);
return 0;
}

The output is:

Comparing integers a and b the result is : -1
Comparing double i and j the result is : 1

As you can see, we can call the compare function using integers as arguments or even double as arguments. It doesn’t matter because the function is a generic function. When the compiler comes to:

    compare(a,b);

it knows that a and b are integers. So it will create a specific instance of the compare function to handle integers. In other words, it will create an instance in which

    mytype=int

Of course you will not see all this happening. The compiler does it automatically. Similarly for:

compare(i,j);
mytype=double

By the way, ‘mytype’ is a generic type parameter.

Remember: You needn’t feel restricted to the use of only one ‘mytype’ within the template function. You can have mytype1, mytype2 etc… Again you can even use the standard parameters (like integer, double etc.) along with generic type parameters.

An Alternative (but crude) Method

#include <iostream>
using namespace std;

#define max(a,b) (a>b?a:b)

int main( )
{
int a,b;
double i,j;
a=5;
b=10;
i=1.45;
j=1.35;
cout<<endl<<max(i,j);
cout<<endl<<max(a,b);
return 0;
}

The output would be:

1.45
10

As you can see, the use of macros for functions seems to act as good as a template would act. But there are some problems with this:

The biggest problem would be when you compare using the unary operators:

cout<<endl<<max(a++,--b);

you would expect that the compiler should now compare between a++(6) and –b(which would be 9) and give a result of 9. But the output will be 8. Why? It’s because of the way the macros work. When the compiler sees max(a++,--b), it will substitute this in the function definition as:

(a++)>(--b) ? (a++): (--b)

The end result is that it decrements ‘b’ two times.

You won’t have this sort of problem when you make use of C++ inline function. And you also won’t have the problem when you make use of template functions.


Template Classes

In this case, we make the member data types of generic type. This is done whenever the functions performed by the class are the same (irrespective of the data type of the members). For instance, if you take the working of a stack the working is the same whether the data are integers or characters. Hence in such cases you can create a generic stack class that can operate on any type of data.

The syntax to create a class similar to creating a template function.

template <class mytype>
class name-of-class
{
//body of class
};

To create an object belonging to the class:

name-of-class <data-type> object-name;

An example should make it clear; here we are just going to pass two different types of data to a class and use a member function to display the two member data.

#include <iostream>
using namespace std;

template<class mytype1, class mytype2>
class display
{ private:
mytype1 a;
mytype2 b;

public:
display(mytype1 x, mytype2 y)
{
a=x;
b=y;
} void show( )
  {
cout<<endl<<"The values are : "<<a<<" , "<<b;
}
};

int main( )
{ display<int,char> ob1(12,'d');
display<int,double> ob2(20,12.123);
ob1.show( );
ob2.show( );
return 0;
}

The output is:

The values are : 12 , d
The values are : 20 , 12.123

The above program shouldn’t pose much difficulty for understanding. You might be wondering as to where class templates might be really useful? Consider the problem we have with arrays in C++. When you create an array of a fixed size and in your program if you exceed the limit of the array, the compiler will not issue any error message. Instead it will continue and your results will be ambiguous. The problem is that there is no array boundary checking in C++ as there is in some other languages (like MATLAB – in MATLAB the compiler will never let you exceed the boundary limits and will produce an error message saying so). Thus, in C++ you can make your own generic array class and overload the [ ] operator such that it will check to see whether the index number specified lies within the size of the array. Else it should display an error message and terminate the program. Try it out.


Go back to the Contents Page 2


Copyright © 2004 Sethu Subramanian All rights reserved.