Exception Handling
Exception Handling
Lecture # 20
Outline
• Exceptions
• Multiple Exceptions
• Exception Notes
2
Exceptions
• Exceptions provide a systematic, object-
oriented approach to handling run-time errors
generated by C++ classes.
• Exceptions are errors that occur at runtime.
• They are caused by a wide-variety
exceptional circumstance, such as:
– running out of memory
– not being able to open a file
– trying to initialize an object to an impossible value
3 – using an out-of-bounds array index
Why Do We Need Exceptions?
• Why do we need a new mechanism to handle
errors?
• In C/C++ programs, an error is often signaled
by returning a particular value from the
function in which it occurred.
• Example: disk file functions often return null
or 0 to signal an error.
• Each time we call these functions, we check
4
the return value.
Why Do We Need Exceptions?
if(somefunc() == ERROR_RETURN_VALUE)
//handle the error or call error-handler function
else
//proceed normally
if(anotherfunc() == null)
//handle the error or call error-handler function
else
//proceed normally
if(thirdfunc() == 0)
//handle the error or call error-handler function
else
5
//proceed normally
Why Do We Need Exceptions?
• One problem with this approach is that every
single call to such a function must be
examined by the program.
• Surrounding each function call with an
if…else statement, and adding statements to
handle the error (or call an error handler
routine), requires a lot of code and makes the
listing complex and hard to read.
• The problem become more complex when
classes are used, since errors may take place
6 without a function being explicitly called.
Why Do We Need Exceptions?
• Example: suppose an application defines
objects of a class
normal return
good call Code that
interacts with
normal return
class
bad call
Error
Catch block
Displays error
message, etc.
10
Exception Syntax
• The exception mechanism uses 3 new C++
keywords:
– throw
– catch
– try
11
Exception Syntax
class AClass
{
public:
class AnError //exception class
{
};
void func()
{
if(/*error condition*/)
throw AnError(); //throw exception
}
12
};
Exception Syntax
int main()
{
try
{
AClass obj1;
obj1.func();
}
catch(AClass::AnError)
{
//tell user about error, etc.
}
return 0;
}
13
Exception Syntax
• An exception class, AnError, is specified in the public
part of AClass.
• In AClass’s member functions we check for errors.
• If we find one, we throw an exception, using the
keyword throw followed by the constructor of the
class.
– throw AnError(); // followed by constructor for AnError class.
• In the main part of the program we enclose any
statements that interact with AClass member in a try
block.
• If any of these statements causes an error to be
detected in an AClass member function, an exception
will be thrown and control will go to the catch block
that immediately follows the try block.
14
A Simple Exception Example
class Stack void push(int var)
{ {
private: if(top>=2)
int data[3]; throw Range();
int top; data[++top]=var;
public: }
class Range int pop()
//exception class for {
stack if(top<0)
{/*empty class body*/}; throw Range();
Stack() { return data[top--];
top=-1; }
} };
15
A Simple Exception Example
#include"stack.h" cout<<s1.pop()<<endl;
#include<iostream> cout<<s1.pop()<<endl;
using namespace std; cout<<s1.pop()<<endl;
void main() //stack empty
{
}
Stack s1;
catch(Stack::Range)
try
{ {
s1.push(11); cout<<"Exception: stack
s1.push(22); full or empty"<<endl;
s1.push(33); }
//s1.push(44);//stack full cout<<"after catch"<<endl;
cout<<s1.pop()<<endl; }
16
Specifying the Exception Class
• The program first specifies an exception class
within the stack class.
– class Range //exception class for stack
– {/*empty class body*/};
• Example:
22
Multiple Exceptions
class Stack void push(int var)
{ {
private: if(top>=2)
int data[3]; throw Full();
data[++top]=var;
int top;
}
public:
int pop()
class Full {
{/*empty class body*/}; if(top<0)
class Empty throw Empty();
{/*empty class body*/}; return data[top--];
Stack() }
{top=-1;} };
23
Multiple Exceptions
#include<iostream> cout<<s1.pop()<<endl;//stac
k empty
using namespace std;
}
void main() { catch(Stack::Full)
Stack s1; {
try { cout<<"Exception: stack
full"<<endl;
s1.push(11);
}
s1.push(22);
catch(Stack::Empty)
s1.push(33); {
//s1.push(44);//stack full cout<<"Exception: stack
cout<<s1.pop()<<endl; empty"<<endl;
}
cout<<s1.pop()<<endl;
cout<<"after catch"<<endl;
cout<<s1.pop()<<endl; }
24
Exceptions with Arguments
• Throwing an exception involves not only
transferring control to the handler, but also
creating an object of the exception class by
calling its constructor.
• We can use this object for providing more
information about what caused an exception.
– If we add data members to the exception class, we
can initialize them when we create the object.
– The exception handler can then retrieve the data
from the object when it catches the exception.
25
Exceptions with Arguments
#include<iostream> InchesEx(string or, float in)
#include<string> {origin=or; ivalue=in;}
using namespace std; };
class Distance Distance():feet(0),inches(0.0){}
{ Distance(int ft,float in)
private: {
int feet; if(in>=12.0)
float inches; throw InchesEx("2-arg
public: constructor",in);
class InchesEx feet=ft;
{ inches=in;
public: }
string origin; //for name void readDist();
of function void showDist()const;
float ivalue; //for faulty };
inches value
26
Exceptions with Arguments
#include"distance.h" void Distance::
void Distance::readDist() showDist() const
{ {
cout<<"\nEnter feet: "; cout<<feet<<endl
cin>>feet; <<inches<<endl;
cout<<"\nEnter inches: "; }
cin>>inches;
if(inches>=12.0)
throw
InchesEx("readDist
function",inches);
}
27
Exceptions with Arguments
#include"distance.h"
void main() {
try {
Distance dist1(17,3.5);
Distance dist2;
dist2.readDist();
dist1.showDist();
dist2.showDist();
}
catch(Distance::InchesEx ix)
{
cout<<"Initialization error in: "<<ix.origin<<endl
<<"Inches value is too large: "<<ix.ivalue<<endl;
}
28 }
Exceptions with Arguments
• There are three parts to the operation of
passing data when throwing an exception:
– Specifying the data members and a constructor for
the exception class.
• Example:
– throw InchesEx("2-arg constructor",in);
31
Extracting Data from the Exception Object
33
The bad_alloc Class
#include<iostream>
using namespace std;
void main() {
const unsigned long SIZE=100000;
char *ptr;
try {
ptr=new char[SIZE];
}
catch(bad_alloc) {
cout<<"bad_alloc exception: can't allocate memory"<<endl;
return;
}
delete[] ptr;
cout<<"memory use is successful"<<endl;
34
}
Exception Notes
• Function Nesting
– The statement that causes an exception
need not to be located directly in the try
block
• it can also be in a function that is called by a
statement in the try block
• or in a function called by a function that is called
by a statement in the try block, and so on.
– We only need to install a try block on the
program’s upper level.
35
Exception Notes
• Exceptions should not be used for every kind
of error.
• They impose a certain overhead in terms of
program size and in time.
• Example:
– Exceptions should not be used for for user input
errors.
– Instead the program should use normal decisions
and loops to check the user’s input and request the
user to try again if necessary.
36
Exception Notes
• Destructor Called Automatically
– The exception mechanism is surprisingly
sophisticated.
– When an exception is thrown, a destructor
is called automatically for any object that
was created by the code up to that point in
the try block.
– The exception mechanism guarantees that
the code in the try block will have been
reset, at least as far as the existence of
objects is concerned.
37
Exception Notes
• Handling Exceptions
– When we catch an exception, we get a
chance to either continue program
execution or terminate the program.
– Exception mechanism gives us a chance to
• indicate the source of error to the user
• perform any necessary clean-up
• or continue program execution, again from the
start of the try block, after fixing the error
38