Exceptions
Contents
Object Oriented Style
Basics
An exception is thrown by a function. If that function does not handle the exception then it is thrown again to the function that called it and so on. The exception object is kept in a special memory but the C++ standard does not madate where and the implementation is left to the compiler. It is often in a speical heap but the not regular heap that we create objects in using "new" . It's only used by the exception handling mechanism. It is not going to be stored on the stack because if there are many functions in a chain and we are destroying each stack frame then we have to keep copying the exception obect.
File: except1.cpp
#include <iostream> #include <fstream> #include <string> using namespace std; int ErrorCode = 0 ; int divideOperation1( int x1, int y1 ) { ErrorCode = 0 ; if ( y1 == 0 ) { ErrorCode = -1 ; return 0 ; } return ( x1 / y1 ) ; } int divideOperation2( int x1, int y1 ) { ErrorCode = 0 ; if ( y1 == 0 ) { throw "Divide by zero." ; } return ( x1 / y1 ) ; } int main() { divideOperation1 ( 4 , 0 ) ; if ( ErrorCode == -1 ) cout << "Error divisor is zero." << endl ; try { divideOperation2 ( 4 , 0 ) ; } //catch ( const string& str1 ) catch ( const char* str1 ) { cout << str1 << endl ; } return 0; }
Output:
$ ./a.exe
Error divisor is zero.
Divide by zero.
This program shows the old way of handling errors using the function:
"divideOperation1" and the new way in the function ""divideOperation2" .
if ( y1 == 0 )
{
throw "Divide by zero." ;
}
This code is inside the function "function2" . What happens when
"throw" is encountered ? In this case there is no catch otherwise control
will move to the catch part. The system will clean up any local objects
and the function will not execute any more code and the exception being
thrown "const char*" is thrown to the calling code.
try
{
divideOperation2 ( 4 , 0 ) ;
}
catch ( const char* str1 )
{
cout << str1 << endl ;
}
The "divideOperation2" in the calling code is enclosed in a "try" block so if it throws
an exception the control comes to the catch block. If the object being thrown matches
the catch argument then the catch code is executed. The code following the "throw" is not
executed. So if there were any statements followig the code "throw Divide by zero." ; they
would not be executed. The local objects get destroyed as the function comes out with the
throw statement.
If the argument is not caught
then it will be passed to the calling function. If the calling function is the "main"
function and the exception is not caught then the program terminates.
File: except2.cpp
#include <iostream> #include <fstream> #include <string> using namespace std; int ErrorCode = 0 ; int divideOperation1( int x1, int y1 ) { ErrorCode = 0 ; if ( y1 == 0 ) { ErrorCode = -1 ; return 0 ; } return ( x1 / y1 ) ; } int divideOperation2( int x1, int y1 ) { ErrorCode = 0 ; if ( y1 == 0 ) { throw "Divide by zero." ; } return ( x1 / y1 ) ; } int main() { divideOperation1 ( 4 , 0 ) ; if ( ErrorCode == -1 ) cout << "Error divisor is zero." << endl ; divideOperation2 ( 4 , 0 ) ; cout << "End of Main." << endl ; return 0; } $ g++ except2.cpp ; ./a.exe Error divisor is zero. terminate called after throwing an instance of 'char const*' Aborted (core dumped) In the above code we have modified "except2.cpp" to have the statements: divideOperation2 ( 4 , 0 ) ; cout << "End of Main." << endl ; Since the exception is not caught and we are in the "main" function the system will not execute any more statements ( "End of Main" is not executed ) and the program will abort as shown in the output.There is a slight disadvantage to the exception handling and that is the control moves to the catch block and it may be difficult to retry the function calls as we are out of the normal coding block.
Excercise
1) What does the below program print ?File: basic_ex1.cpp
#include <iostream> #include <fstream> using namespace std; class A { public: A() { cout << "A: constructor: " << endl ; } ~A() { cout << "A: destructor: " << endl ; } }; void function2() { A objectA1 ; try { cout << "Inside function2: Step 1" << endl ; throw 10 ; cout << "Inside function2: Step 2" << endl ; } catch( int& x1 ) { cout << "Inside function2: Catch Step 1" << endl ; throw x1 ; cout << "Inside function2: Catch Step 2" << endl ; } cout << "End of function2." << endl ; } void function1() { A objectA1 ; cout << "Inside function1: Step 1" << endl ; function2() ; cout << "End of function1." << endl ; //A } int main() { try { function1() ; cout << "After function 1 in main." << endl ; //B } catch ( int& x1 ) { cout << "Inside catch. main" << endl ; } cout << "End of main:" << endl ; return 0; }