In a procedural language the error handling is either done by checking the return value of a function or checking some other variable that contains the error. The pseudo code can look like:
result = function1() ;
if ( result < 0 )
//Handle error
function2() ;
if ( ErrorCode == 100 )
//Handle error
The code can easily become very messy . Another way to handle errors and this is usually a feature in object oriented programming is use Exceptions. The above will instead look like:
try
{
result = function1() ;
function2() ;
}
catch ( Exception except )
{
//Any error in the try block causes control to come
//to the catch block.
}
File: "except1.cpp"
#include <iostream>#include <fstream>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 char* str1 ) { cout << str1 << endl ; } return 0;}
Output:
$ ./a.exe
Error divisor is zero.
Divide by zero.
There is a slight disadvantage to the exception handling and that is the control movies to the catch block and it may be difficult to retry the function calls as we are out of the normal coding block.
We can also have multiple catch statements corresponding to our try block.
#include <iostream>#include <fstream>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 ; // throw 1 ; try { throw 5 ; //throw statement can occur anywhere divideOperation2 ( 4 , 0 ) ; } catch ( const char* str1 ) { cout << str1 << endl ; } catch ( int& e1 ) { cout << "Integer Exception" << endl ; } return 0;}
If an exception is thrown and it is not caught in that function then it will be thrown again to the calling function and the process can repeat.
File: "except3.cpp"
#include <iostream>#include <fstream>using namespace std;void function2(){ throw 10 ;}void function1(){ function2() ;}int main(){ try { function1() ; } catch ( int& e1 ) { cout << "Integer Exception" << endl ; } return 0;}
Output:
$ ./a.exe
Integer Exception
If the exception is not thrown then the main program aborts.
File: "except4.cpp"
#include <iostream>#include <fstream>using namespace std;void function2(){ throw 10 ;}void function1(){ function2() ;}int main(){ function1() ; return 0;}
Output:
$ ./a.exe
terminate called after throwing an instance of 'int'
Aborted (core dumped)
We can have nested try catch blocks also.
File: "except5.cpp"
#include <iostream>#include <fstream>using namespace std;void function2(){ throw 10 ;}void function1(){ function2() ;}int main(){ try { try { function1() ; } catch ( int& e1 ) { cout << "Integer Exception" << endl ; throw e1 ; } } catch( int& e2 ) { cout << "Outer Integer Exception" << endl ; } return 0;}
Output:
$ g++ except5.cpp ; ./a.exe
Integer Exception
Outer Integer Exception
Exercise
1)
What does the following print ?
#include <iostream>#include <fstream>using namespace std;void function2(){ try { cout << "Inside function2 1." << endl ; throw 10 ; cout << "Inside function2 2." << endl ; } catch( int x1 ) { cout << "Inside function2 catch." << endl ; throw x1 ; }}void function1(){ try { cout << "Inside function1 1." << endl ; function2() ; } catch( const char* str1 ) { cout << "Inside function1 catch." << endl ; }}int main(){ try { try { function1() ; } catch ( int& e1 ) { cout << "Integer Exception" << endl ; } } catch( int& e2 ) { cout << "Outer Integer Exception" << endl ; } return 0;}
2)
File: "ex2.cpp"
#include <iostream>#include <fstream>using namespace std;/* This functions takes 2 values from the user and if any value is out of range throws an exception.*/void function1( int& low , int& high ){ cout << "Enter low value:" << endl ; cin >> low ; cout << "Enter high value:" << endl ; cin >> high ; if ( low < 0 || high > 100 ) throw "Values are out of range." ;}int main(){ //TO DO //Put a try catch around fucntion1 to catch the error function1() ; return 0;}
We can use the "..." to catch an exception of any type .
File: "except6.cpp"
#include <iostream>#include <fstream>using namespace std;int main(){ try { throw "Some error" ; } catch ( int& e1 ) { cout << "Integer Exception" << endl ; } catch( ... ) { cout << "Default Handler." << endl ; } return 0;}
Output:
$ g++ except6.cpp ; ./a.exe
Default Handler.
We can also throw an object of our own class.
File: "except7.cpp"
#include <iostream>#include <fstream>using namespace std;class MyException { public: string messg ; MyException( string str1 ) { messg = str1 ; }};int main(){ try { throw MyException("Error") ; } catch ( MyException& e1 ) { cout << e1.messg << endl ; } return 0;}
If we have a hierarchy then we can throw a derived exception and catch it with the base class.
File: "except8.cpp"
#include <iostream>#include <fstream>using namespace std;class MyExceptionBase { public: string messg ; MyExceptionBase( string str1 ) { messg = str1 ; }};class MyException : public MyExceptionBase { public: MyException( string str1 ) : MyExceptionBase( str1 ) { }};int main(){ try { throw MyException("Error") ; } catch ( MyExceptionBase& e1 ) { cout << e1.messg << endl ; } return 0;}
fd
C++ provides standard exceptions that can be used to catch exceptions thrown by the language.
File: "mem1.cpp"
// bad_alloc standard exception#include <iostream>#include <exception>using namespace std;int main () { try { int* myarray ; while( 1 ) myarray = new int[1000000]; } catch (exception& e) { cout << "Standard exception: " << e.what() << endl; } return 0;}
$ g++ mem1.cpp ; ./a.exe
Standard exception: std::bad_alloc
We can also derive our own class from the exception class.
File: "mem2.cpp"
// using standard exceptions#include <iostream>#include <exception>using namespace std;class myexception: public exception{ virtual const char* what() const throw() { return "My exception happened"; }} ;int main () { try { myexception myex ; throw myex; } catch (exception& e) { cout << e.what() << '\n'; } return 0;}