***Welcome to ashrafedu.blogspot.com * * * This website is maintained by ASHRAF***

Saturday, July 24, 2021

Standard Template Library (STL)

The Standard Template Library (STL) is a set of C++ template classes to provide common programming data structures and functions such as lists, stacks, arrays, etc. It is a library of container classes, algorithms, and iterators. 

STL is mainly composed of:

  1. Algorithms
  2. Containers
  3. Iterators

STL is a generic library , i.e a same container or algorithm can be operated on any data types.

Algorithms in STL

STL provide number of algorithms that can be used of any container, irrespective of their type. Algorithms library contains built in functions that perform complex algorithms on the data structures.

Example: one can reverse a range with reverse() function, sort a range with sort() function, search in a range with binary_search() and so on. 

Algorithm library provides abstraction, i.e you don't necessarily need to know how the the algorithm works.

Containers in STL

Container library in STL provide containers that are used to create data structures like arrays, linked list, trees etc.

These container are generic, they can hold elements of any data types, for example: vector can be used for creating dynamic arrays of char, integer, float and other types.

Iterators in STL

Iterators in STL are used to point to the containers. Iterators actually act as a bridge between containers and algorithms.

Example: sort() algorithm have two parameters, starting iterator and ending iterator, now sort() compare the elements pointed by each of these iterators and arrange them in sorted order, thus it does not matter what is the type of the container and same sort() can be used on different types of containers.

Class Templates and Inheritance

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. 

If new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

Example:

template<class T>

class Base

{

private:

T data;

public:

void set(const T& val)

{

data= val;

}

};

template<class T>

class Derived: public Base<T>

{

public:

void set(const T& val);

};

template<class T>

void Derived<T> :: set(const T& v)

{

Base<T>::set(v);

}

 

The derived class may itself have template parameters. Please note there must be enough template parameters in the derived class to satisfy the requirements of the base class.

There is no requirement that your base class be a template. It is quite possible to have a template class inherit from a ‘normal’ class.

Class Templates

Templates may also be used to create generic classes and abstract data types. Class templates allow you to create one general version of a class without having to duplicate code to handle multiple data types. 

Declaring a class template is very similar to declaring a function template. First, a template prefix, such as template<class T>, is placed before the class declaration. As with function templates, T (or identifier choose to use) is a data type parameter. Then, throughout the class declaration, the data type parameter is used where you wish to support any data type.

Example:

template <class T>

class MyTemplate {

T element;

public:

MyTemplate (T arg)

{element=arg;}

T divideBy2 ()

{return element/2;}

};

void main()

{

MyTemplate<int> obj(10);

obj.divideBy2();

}

 

To declare an object of this class to store integer values of type int we would write:

 

MyTemplate<int> obj;

Overloading with Function Templates

Function templates may be overloaded. As with regular functions, function templates are overloaded by having different parameter lists.

// This program demonstrates an overloaded function template.

#include <iostream>

template <class T>

T sum(T val1, T val2)

{

return val1 + val2;

}

template <class T>

T sum(T val1, T val2, T val3)

{

return val1 + val2 + val3;

}

void main()

{

double num1, num2, num3;

// Get two values and display their sum.

cout << "Enter two values: ";

cin >> num1 >> num2;

cout << "Their sum is " << sum(num1, num2) << endl;

// Get three values and display their sum.

cout << "Enter three values: ";

cin >> num1 >> num2 >> num3;

cout << "Their sum is " << sum(num1, num2, num3) << endl;

}

 

There are two overloaded versions of the sum function in program. The first version accepts two arguments, and the second version accepts three.

There are other ways to perform overloading with function templates as well. For example, a program might contain a regular (nontemplate) version of a function as well as a template version. As long as each has a different parameter list, they can coexist as overloaded functions.

Function Templates

A function template is a “generic” function that can work with any data type.

Function templates allows us to write a single function definition that works with many different data types, instead of having to write a separate function for each data type used. The programmer writes the specifications of the function, but substitutes parameters for data types. When the compiler encounters a call to the function, it generates code to handle the specific data type(s) used in the call.

Here is a function template for the square function:

template <class T>

T square(T number)

{

return number * number;

}

The beginning of a function template is marked by a template prefix , which begins with the key word template .

Set of angled brackets that contain one or more generic data types are used in the template. A generic data type starts with the key word class followed by a parameter name that stands for the data type. After this, the function definition is written as usual, except the type parameters are substituted for the actual data type names.

 

Example:

// This program uses a function template.

#include <iostream.h>

// Template definition for square function.

template <class T>

T square(T number)

{

return number * number;

}

void main()

{

int userInt; // To hold integer input

double userDouble; // To hold double input

cout << "Enter an integer and a floating-point value: ";

cin >> userInt >> userDouble;

cout << "Here are their squares: ";

cout << square(userInt) << " and " << square(userDouble) << endl;

}

 

A function template is merely the specification of a function and by itself does not cause memory to be used. An actual instance of the function is created in memory when the compiler encounters a call to the template function.

 

Function Templates with Multiple Types

While creating templates, it is possible to specify more than one type. More than one generic data type can be used in a class template. They are declared as a comma-separated list within the template as below

Syntax:

template<class T1, class T2, ...>

class classname

{

      ...

      ...

};

 

Example: CPP program to illustrate Class template with multiple parameters

#include<iostream>

using namespace std;

 

// Class template with two parameters

template<class T1, class T2>

class Test

{

                                              T1 a;

                                              T2 b;

                          public:

                                              Test(T1 x, T2 y)

                                              {

                                                   a = x;

                                                   b = y;

                                              }

                                              void show()

                                              {

                                                   cout << a << " and " << b << endl;

                                              }

};

void main()

{

                          // instantiation with float and int type

                          Test <float, int> test1 (1.23, 123);

                         

                          // instantiation with float and char type

                          Test <int, char> test2 (100, 'W');

                         

                          test1.show();

                          test2.show();

}

 

Because the function parameters are specified with different types, the function generated from this template can accept two arguments of different types.

Handling the bad_alloc Exception

When the new operator fails to allocate memory, C++ throws a bad_alloc exception. The bad_alloc exception type is defined in the new header file, so any program that attempts to catch this exception should have the following directive:

 #include <new.h>

 Here is the general format of a try/catch construct that catches the bad_alloc exception:

 

try

{

// Code that uses the new operator

}

catch (bad_alloc)

{

// Code that responds to the error

}

 

Sunday, July 4, 2021

Rethrowing an Exception

It is possible for try blocks to be nested. With nested try blocks, it is sometimes necessary for an inner exception handler to pass an exception to an outer exception handler. Sometimes, both an inner and an outer catch block must perform operations when a particular exception is thrown. These situations require that the inner catch block rethrow the exception so the outer catch block has a chance to catch it.

A catch block can rethrow an exception with the throw; statement.

#include <iostream.h>

void MyHandler()

{

   try

   {

       throw “hello”;

   }

   catch (const char*)

   {

   cout <<”Caught exception inside MyHandler\n”;

   throw;     //rethrow char* out of function

   }

}

int main()

{

   cout<< “Main start”;

try

   {

       MyHandler();

   }

   catch(const char*)

   {

      cout <<”Caught exception inside Main\n”;

   }

       cout << “Main end”;

       return 0;

}

 

Output :

Main start

Caught exception inside MyHandler

Caught exception inside Main

Main end


Multiple Catch Statements - Catching all Exceptions

In some situations the program segment has more than one condition to throw an exception.In such case more than one catch blocks can be associated with a try block as shown below

try

{//try block

}

catch(type1 arg)

//catch block1

}

catch(type 2 arg)

{

//catch block 2

}

……………..

…………….

catch (type N arg)

{

//catch block N

}

When an exception is thrown, the exception handlers are searched in order for an appropriate match. The first handler that yields a match is executed. After executing the handler, the control goes to the first statement after the last catch block for that try. When no match is found, the program is terminated.

If in some case the arguments of several catch statements match the type of an exception, then the first handler that matches the exception type is executed.

Catch All Exceptions:-

In some cases when all possible type of exceptions cannot be anticipated and may not be able to design independent catch handlers to catch them, in such situations a single catch statement is forced to catch all exceptions instead of certain type alone. This can be achieved by defining the catch statement using ellipses as follows

catch(. . .)

{

//statement for processing all exceptions

}

Example:

#include <iostream.h>

void test(int x)

{

try

{

if (x== 0) throw x; //int

if ( x== -1) throw ‘x’; //char

if ( x== 1) throw 1.0; //float

}

catch(. . .) //catch all

{

cout<<”caught an exception \n”;

}

}

int main()

{

cout<<”testing generic catch\n”;

test(-1);

test(0);

test(1);

}

The catch(. . .) can be used as a default statement along with other catch handlers so that it can catch all those exceptions that are not handled explicitly.