820 likes | 833 Views
Learn about exceptions, function templates, and Standard Template Library (STL) in C++ programming. Understand how to handle exceptions and use templates effectively in your code.
E N D
Chapter 16: Exceptions, Templates, and the Standard Template Library (STL) Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda
Topics 16.1 Exceptions 16.2 Function Templates 16.3 Class Templates 16.4 Class Templates and Inheritance 16.5 Introduction to the Standard Template Library
16.1 Exceptions An exception is a condition that occurs at execution time and makes normal continuation of the program impossible When an exception occurs, the program must either terminate or jump to special code for handling the exception. The special code for handling the exception is called an exception handler
Exceptions, Templates and STL Exceptions • Indicate that something unexpected has occurred or been detected • Allow program to deal with the problem in a controlled manner • Can be as simple or complex as program design requires • The line containing the throw statement is the throw point • Control is passed to another part of the program known as the exception handler • When an exception is thrown by a function, the function aborts
Exceptions – Key Words • Exception: object or value that signals an error • Throw an exception: send a signal that an error has occurred • throw – followed by an argument, is used to throw an exception • Catch/Handle an exception: process the exception; interpret the signal • try – followed by a block { }, is used to invoke code that throws an exception • catch – followed by a block { }, is used to detect and process exceptions thrown in preceding try block. Takes a parameter that matches the type thrown.
Exceptions, Templates and STL Coding for Exceptions int main() { int numerator[3]={10,0,10}; int denominator[3]= {2,10,0}; double answer; for (int i=0; i<3;i++) { answer = divide(numerator[i], denominator[i]); cout<<numerator[i]<<" divided by "<<denominator[i] <<" = "<<answer<<endl; } cout<<endl<<endl; for (int i=0; i<3;i++) { answer = divide_throw(numerator[i], denominator[i]); cout<<numerator[i]<<" divided by "<<denominator[i]<<" = "<<answer<<endl; } return 0; }
Exceptions, Templates and STL Coding for Exceptions double divide(int n, int d) { if (d==0) { cout<<"ERROR: Cannot divide by zero "; return 0; } else return static_cast<double>(n)/d; } double divide_throw(int n, int d) { if (d==0) { throw "ERROR: Cannot divide by zero\n"; } else return static_cast<double>(n)/d; }
Exceptions, Templates and STL Coding for Exceptions - Output Output from function divide 10 divided by 2 = 5 0 divided by 10 = 0 ERROR: Cannot divide by zero 10 divided by 0 = 0 Output from function divide_throw 10 divided by 2 = 5 0 divided by 10 = 0 This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
Throwing an Exception • Code that detects the exception must pass information to the exception handler. This is done using a throw statement: throw "Emergency!" throw 12; • In C++, information thrown by the throw statement may be a value of any type
Catching an Exception • Block of code that handles the exception is said to catch the exception and is called an exception handler • An exception handler is written to catch exceptions of a given type: For example, the code catch(char *str) { cout << str; } can only catch exceptions of C-string type
Catching an Exception Another example of a handler: catch(int x) { cerr << "Error: " << x; } This can catch exceptions of type int
Connecting to the Handler Every catch block is attached to a try block of code and is responsible for handling exceptions thrown from that block try { } catch(char e1) { // This code handles exceptions // of type char that are thrown // in this block }
Execution of Catch Blocks The catch block syntax is similar to a that of a function Catch block has a formal parameter that is initialized to the value of the thrown exception before the block is executed
Exceptions, Templates and STL Exceptions – Flow of Control • A function that throws an exception is called from within a try block • If the function throws an exception, the function terminates and the try block is immediately exited. • A catch block to process the exception is searched for in the source code immediately following the try block. • If a catch block is found that matches the exception thrown, it is executed. • If no catch block that matches the exception is found, the program terminates.
Exceptions, Templates and STL THIS WORKS in Code::Blocks char* msg; msg = "ERROR: Cannot divide by zero.\n"; if (denominator == 0) throw msg;
Exceptions, Templates and STL What Happens in the Try/Catch Construct
Exception Example An example of exception handling is code that computes the square root of a number. It throws an exception in the form of a C-string if the user enters a negative number
Example int main( ) { try { double x; cout << "Enter a number: "; cin >> x; if (x < 0) throw "Bad argument!"; cout<<"Squarerootof"<< x <<" is"<< sqrt(x); } catch(char *str) { cout << str; } return 0; }
Flow of Control • Computer encounters a throw statement in a try block • The computer evaluates the throw expression, and immediately exits the try block • The computer selects an attached catch block that matches the type of the thrown value, places the value in the catch block’s formal parameter, and executes the catch block
Exceptions, Templates and STL What if no exception is thrown?
Exceptions, Templates and STL Catch Exception and Reprompt int main() { int num1, num2; // To hold two numbers double quotient; // To hold the quotient of the numbers bool goodResult; //test if no exception thrown do{ cout << "Enter two numbers: "; cin >> num1 >> num2; goodResult=true; try { quotient = divide(num1, num2); cout << "The quotient is " << quotient << endl; } catch (char *exceptionString) { goodResult=false; cout <<exceptionString; } } while (!goodResult); cout << "End of the program.\n"; return 0; }
Exceptions, Templates and STL Exceptions - Notes • An integer can be thrown to signal a predefined error code try { quotient = divide(num1, num2); cout << "The quotient is " << quotient << endl; } catch (int exceptionInt) { goodResult=false; cout <<“Error code”<<exceptionInt; } In the function write: if (denominator == 0) throw 333; and then look up the code in a library or table
Uncaught Exception • An exception may be uncaught if • there is no catch block with a data type that matches the exception that was thrown, or • it was not thrown from within a try block • The program will terminate in either case
Handling Multiple Exceptions Multiple catch blocks can be attached to the same block of code. The catch blocks should handle exceptions of different types try{...} catch(int iEx){ } catch(char *strEx){ } catch(double dEx){ }
Throwing an Exception Class • An exception class can be defined and thrown • Catch block must be designed to catch an object of the exception class • Exception class object can pass data to exception handler via data members • An exception class may have: • no members: used only to signal an error • members: pass error data to catch block • A class can have more than one exception class
Exceptions, Templates and STL Exception class definition
Exceptions, Templates and STL Program Output
Exceptions, Templates and STL Handling Multiple Exceptions • To differentiate between a negative width and length, two classes can be created and each called based on the type of error • In Rectangle.h include: public: class NegativeWidth { }; // Exception class for a negative width class NegativeLength { }; // Exception class for a negative length • and in main change the try blocks to the following: try { myRectangle.setWidth(width); myRectangle.setLength(length); cout << "The area of the rectangle is “ << myRectangle.getArea() << endl; } catch (Rectangle::NegativeWidth) { cout<<"Error: A negative value was given "<< "for the rectangle's width.\n"; } catch (Rectangle::NegativeLength) { cout<<"Error:A negative value was given "<< "for the rectangle's length.\n"; }
Recovering From Exceptions • Within the catch block, prompt the user to re-enter the correct length or width // Get the rectangle's width. cout << "Enter the rectangle's width: "; cin >> width; // Store the width in the myRectangle object. while (tryAgain) { try { myRectangle.setWidth(width); // If no exception was thrown, then the // next statement will execute. tryAgain = false; } catch (Rectangle::NegativeWidth) { cout << "Please enter a non-negative width: "; cin >> width; } } // Get the rectangle's length. cout << "Enter the rectangle's length: "; cin >> length; // Store the length in the myRectangle object. tryAgain = true; while (tryAgain) { try { myRectangle.setLength(length); // If no exception was thrown, then the // next statement will execute. tryAgain = false; } catch (Rectangle::NegativeLength) { cout << "Please enter a non-negative length: "; cin >> length; } } Exceptions, Templates and STL
Recovering From Exceptions Enter the rectangle's width: -4 Please enter a non-negative width: -6 Please enter a non-negative width: 6 Enter the rectangle's length: -9 Please enter a non-negative length: 9 The rectangle's area is 54 Exceptions, Templates and STL
Extracting Data from the Exception Class • Sometimes, we want an exception object to pass data back to the exception handler • We want the Rectangle class not only to signal when a negative value was entered, but to pass back that value as well • This can be accomplished by expanding the exception class with members in which data can be stored. For example: Exceptions, Templates and STL
Exceptions, Templates and STL What Happens After catch Block? • Once an exception is thrown, the program cannot return to throw point. The function executing throw terminates (does not return), other calling functions in try block terminate, resulting in unwinding the stack • If an exception is thrown by the member function of a class object, then the class destructor is called • If objects were created in the try block and an exception is thrown, they are destroyed.
Exceptions, Templates and STL Nested try Blocks • try/catch blocks can occur within an enclosing try block • Exceptions caught at an inner level can be passed up to a catch block at an outer level: catch ( ) { ... throw; // pass exception up } // to next level
Exceptions, Templates and STL Nested try Blocks void doA(){ char *exception1; try{ doB(); } catch(char *exception1) { cout<<"Exception 1 in doA(),rethrown“ <<endl; throw; } } void doB(){ char *exception1; try{ throw exception1; } catch(char *exception1) { cout<<"Exception 1 in doB(),rethrown“ <<endl; throw; } } #include <iostream> using namespace std; void doA(); void doB(); int main() { char *exception1; try{ doA(); } catch(char *exception1) { cout<<"Exception 1 handled in main"<<endl; } return 0; } Exception 1 in doB(),rethrown Exception 1 in doA(),rethrown Exception 1 in main, handled in main
Exception When Calling new If new cannot allocate memory, it throws an exception of type bad_alloc Must #include <new> to use bad_alloc Can invoke new from within a try block, use a catch block to detect that memory was not allocated.
Exceptions, Templates and STL Handling the bad_alloc Exception • When the new operator is unable to allocate the requested amount of memory, a bad_alloc exception is thrown. It can be handled as follows:
16.2 Function Templates Function template: A pattern for creating definitions of functions that differ only in the type of data they manipulate Better than overloaded functions, since the code defining the algorithm of the function is only written once
Exceptions, Templates and STL Function Templates • Function template: a generic function that can work with any data type. • It is a template 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 • The programmer writes the specifications of the function, but substitutes parameters for data types • When called, compiler generates code for specific data types in function call
Exceptions, Templates and STL Function Template Example template prefix template <class T> T square(T num) { return num * num; } generic data type type parameter
Exceptions, Templates and STL Function Template Example template <class T> T square(T num) { return num * num; } • Call a template function in the usual manner: int ival = 3; double dval = 12.5; cout << square(ival); // displays 9 cout << square(dval); // displays 156.25 See projectTemplateSquareFunction
Exceptions, Templates and STL Function Template Swap Example #include <iostream> using namespace std; template <class T> void swapVars(T &var1, T &var2) { T temp; temp = var1; var1 = var2; var2 = temp; }
Exceptions, Templates and STL Function Template Swap Example int main() { char firstChar, secondChar; // Two chars int firstInt, secondInt; // Two ints double firstDouble, secondDouble; // Two doubles // Get and swapVars two chars cout << "Enter two characters: "; cin >> firstChar >> secondChar; swapVars(firstChar, secondChar); cout << firstChar << " " << secondChar << endl; // Get and swapVars two ints cout << "Enter two integers: "; cin >> firstInt >> secondInt; swapVars(firstInt, secondInt); cout << firstInt << " " << secondInt << endl; // Get and swapVars two doubles cout << "Enter two floating-point numbers: "; cin >> firstDouble >> secondDouble; swapVars(firstDouble, secondDouble); cout << firstDouble << " " << secondDouble << endl; return 0; }
A swap Template The logic of both functions can be captured with one template function definition template<class T> void swap(T &x, T &y) { T temp = x; x = y; y = temp; }
Using a Template Function • When a function defined by a template is called, the compiler creates the actual definition from the template by inferring the type of the type parameters from the arguments in the call: inti = 1, j = 2; swap(i,j); • This code makes the compiler instantiate the template with type int in place of the type parameter T • See project TemplateSwap
Function Template Notes A function template is a pattern No actual code is generated until the function named in the template is called A function template uses no memory When passing a class object to a function template, ensure that all operators referred to in the template are defined or overloaded in the class definition
Function Template Notes All data types specified in template prefix must be used in template definition Function calls must pass parameters for all data types specified in the template prefix Function templates can be overloaded – need different parameter lists Like regular functions, function templates must be defined before being called
Where to Start When Defining Templates • Templates are often appropriate for multiple functions that perform the same task with different parameter data types • Develop function using usual data types first, then convert to a template: • add template prefix • convert data type names in the function to a type parameter (i.e., a T type) in the template