380 likes | 644 Views
Chapter 16 – Exceptions, Templates, and the Standard Template Library (STL) . Exceptions are used to signal errors or unexpected events that occur while a program is running.
E N D
Chapter 16 – Exceptions, Templates, and the Standard Template Library (STL) • Exceptions are used to signal errors or unexpected events that occur while a program is running. • We have checked for errors before by placing if statements that checked for the condition or by using assert statements.
Exceptions (cont) • An exceptional condition is a value or an object that signals an error. • When the error occurs, an exception is “thrown.”
Throwing an Exception Rational::Rational ( int numerator, int denominator ) { if ( denominator == 0 ) throw "ERROR: Cannot divide by zero.\n"; this->numerator = numerator; this->denominator = denominator; } // divide
Throw • The line containing a throw statement is called the throw point. • When a throw statement is executed, control is passed to an exception handler. • When an exception is thrown by a function, the function aborts. • Any type can be “thrown”
Handling an Exception • An exception is handled by a try/catch construct. • The try block contains a block of code that may directly or indirectly cause an exception to be thrown. • The catch block contains a block of code that handles the exception.
Example Exception Handler try { Rational q = Rational( num1, num2 ); cout << q << endl; } // try catch ( char *exceptionString ) { cout << exceptionString; } // catch
Handling an Exception (cont) • If divide throws an exception, the exception is caught by the catch statement. • The type of the parameter to the catch statement must be the same as in the throw statement (or class from which it is derived). • Execution continues after the try/catch statement, unless the catch statement does something else.
Uncaught Exceptions • Ways for uncaught exceptions: • No catch statement with a parameter of the correct data type. • The exception is thrown outside a try statement. • In either case, the exception causes the program to abort.
More on Exceptions • Exceptions can be put in classes. This allows us to do more with them. • We can have multiple exception classes. • Exception classes can have parameters that allow information to be returned.
IntMain.cpp – Program (cont) in getInput… throw OutOfRange( input ); in main… try { userValue = range.getInput(); cout << "You entered " << uservalue << endl; } // try catch ( IntRange::OutOfRange ex ) { cout << "That value " << ex.value << " is out of range." << endl; } // catch cout << "End of program." << endl; } // main
Class for exceptions class BadTrait{ private: string msg; public: BadTrait(string errorMsg, int val){ char str[10]; itoa(val,str,10); // integer, string to convert to, number sys msg = errorMsg+str; } string getMsg(){ return msg;} };
How to Throw // add newEle to set only if it is a legal element Set &Set::operator+=(int newEle){ if (newEle <memberMax && newEle >=0) member[newEle]=true; else throw BadTrait("Error: Adding element which is out of range " , newEle); return *this; }
How to catch try{ Traits me; me+=4; me += 5;me +=11; me +=27; }catch (BadTrait b){ cout<< b.getMsg() << endl;}
Unwinding the Stack • When an exception is thrown, the function immediately terminates. • If that function was called by another function, then the calling function terminates as well. • This process continues. • This is called unwinding the stack.
Function Templates • A function template is a “generic” function that can work with any data type. • 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.
Template Example • We want a function that prints out the values of an array. • This function should work with arrays of type int, float, char, or string.
printArray.cpp – Program #include <iostream> #include <string> using namespace std; template< class T> void printArray ( const T *array, const int size ) { for ( int i = 0; i < size; i++ ) { if ( !( i % 10 ) ) cout << endl; cout << array[i] << " "; } // for cout << endl; } // printArray
printArray.cpp – Program (cont) void main ( void ) { const int aSize = 5, bSize = 7, cSize = 6, dSize = 3; int a[ aSize ] = { 1, 2, 3, 4, 5 }; float b[ bSize ] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 }; char c[ cSize ] = "Hello"; string d[ dSize ] = { "I", "love", "CS" }; printArray( a, aSize ); printArray( b, bSize ); printArray( c, cSize ); printArray( d, dSize ); } // main
Generic swap • Suppose we wanted a generic swap. template <class T> void swap ( T &var1, T &var2 ) { T temp; temp = var1; var1 = var2; var2 = temp; } // swap
Template with Multiple Types template <class T1, class T2> void swap ( T1 &var1, T2 &var2 ) { T1 temp; temp = var1; var1 = (T1)var2; var2 = (T2)temp; } // swap
Operators in Template • If arithmetic or relational operators are used in templates, they must be defined for the different types of the templates. • If the operators are not defined for a particular type, the compiler generates an error.
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.
Generic Class • Suppose you wanted to have a class that held a collection of objects. • We want this class to work with different data types. • We could create a different class for each data type, but there is a better solution. • We will look at a class template.
SimpleVector.h – Program template <class T> Class SimpleVector { private: T *aptr; int arraySize; public: SimpleVector ( void ) { aptr = NULL; arraySize = 0; } ; SimpleVector ( int ); SimpleVector ( const SimpleVector & ); ~SimpleVector ( void ); int getSize ( void ) { return arraySize; }; T &operator[] ( const int & ); }; // SimpleVector
SimpleVector.cpp – Program template <class T> SimpleVector<T>::SimpleVector ( int s ) { arraySize = s; aptr = new T [ s ]; assert( aptr ); for ( int i = 0; i < arraySize; i++ ) *( aptr + i ) = 0; } // SimpleVector::SimpleVector template <class T> SimpleVector<T>::~SimpleVector ( void ) { if ( arraySize > 0 ) delete [] aptr; } // SimpleVector::~SimpleVector
Declaring Objects of Class Templates • The declaration of class templates is a little different. • Consider the following examples: • SimpleVector<int> intTable ( 10 ); • SimpleVector<float> floatTable ( 10 ); • In these, the parameter inside the angle brackets replaces the T in the previous declarations.
Class Templates and Inheritance #ifndef SEARCHABLEVECTOR_H #define SEARCHABLEVECTOR_H #include “SimpleVector.h” template <class T> class SearchableVector : public SimpleVector<T> { public: SearchableVector ( int s ) : SimpleVector<T>( s ) { } SearchableVector ( SearchableVector & ); SearchableVector ( SimpleVector<T> &obj ) : SimpleVector<T>( obj ) { } int findItem ( T ); }; // SearchableVector
Introduction to the Standard Template Library (STL) • The Standard Template Library contains many templates for useful algorithms and data structures. • We’ve seen on of these earlier in the book – the vector data type.
Abstract Data Types • The most important data structures in STL are containers and iterators: • Container – a class that stores data and organizes it in some fashion. • Iterator – similar to a pointer and is used to access the individual data elements in a container.
Container Classes • Sequence – organizes data in a sequential fashion similar to an array. • Associative – uses keys to rapidly access elements in the data structure.
More on Iterators • Iterators are associated with containers. • The type of container you have determines the type of iterator you use. • For example, vectors and deques require random-access iterators. • Lists, sets, multisets, maps, and multimaps require bidirectional iterators.
Algorithms • Algorithms are implemented as function templates. • They perform various operations on elements of containers.
Using Vectors – Program #include <iostream> #include <vector> #include <algorithm> using namespace std; void doubleValue ( int &val ) { val *= 2; } // doubleValue void main ( void ) { vector<int> numbers; vector<int>::iterator iter;
Using Vectors – Program (cont) for ( int x = 0; x < 10; x++ ) numbers.push_back( x ); cout << “The numbers in the vector are:\n”; for ( iter = numbers.begin(); iter != numbers.end(); iter++ ) cout << *iter << endl; cout << endl; for_each ( numbers.begin(), numbers.end(), doubleValue ); cout << “The numbers again are:\n”; for ( iter = numbers.begin(); iter != numbers.end(); iter++ ) cout << *iter << endl; cout << endl; } // main