Programming Workshop 2 (CSCI 1061U)
Faculty of Science, Ontario Tech University
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
double d, t;
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
<< "Velocity is: " << d/t << endl;
cout
return 0;
}
Output
./velocity-no-error-checking
Enter distance: 2
Enter time: 0
Velocity is: inf
Avoid executing statements that may lead to those errors
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
double d, t;
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
if (t <= 0) {
<< "Cannot compute velocity" << endl;
cout }
else {
<< "Velocity is: " << d/t << endl;
cout }
return 0;
}
Output
./velocity-error-checking
Enter distance: 2
Enter time: 0
Cannot compute velocity
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
double d, t;
try {
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
if (t <= 0) throw d;
<< "Velocity is: " << d/t << endl;
cout }
catch (double e)
{
<< "Exception raised." << endl;
cout }
<< "Continue ..." << endl;
cout
return 0;
}
Output
./velocity-exception-handling
Enter distance: 3
Enter time: 0
Exception raised.
Continue ...
Separates normal execution from what should be done in exceptional circumstances, keeping logic simple and design clean
Normal execution
try {
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
if (t <= 0) throw d;
<< "Velocity is: " << d/t << endl;
cout }
Code that needs to be executed in exceptional circumstances
catch (double e)
{
<< "Exception raised." << endl;
cout }
if (t <= 0) throw d;
throw
followed by exception typetry {
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
if (t <= 0) throw d;
<< "Velocity is: " << d/t << endl;
cout }
catch (double e)
{
<< "Exception raised." << endl;
cout }
catch (double)
{
<< "Exception raised." << endl;
cout }
throw
statement can throw value of any type, even
user-defined classesIn the following code, exception of type BadTime
is
thrown in case the user enters an invalid value for time.
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class BadTime
{
private:
double t;
;
string n
public:
(double time) : t(time) {
BadTime= "BadTime";
n }
() const { return n; }
string getNamedouble getValue() const { return t; }
};
int main()
{
double d, t;
try {
<< "Enter distance: ";
cout >> d;
cin << "Enter time: ";
cout >> t;
cin
if (t <= 0) throw BadTime(t);
<< "Velocity is: " << d/t << endl;
cout }
catch (BadTime bd)
{
<< "Exception " << bd.getName()
cout << " called with value " << bd.getValue()
<< endl;
}
<< "Continue doing what you were doing." << endl;
cout
return 0;
}
Output
$./velocity-exception-classes
Enter distance: 12
Enter time: 2
Velocity is: 6
Continue doing what you were doing.
$./velocity-exception-classes
Enter distance: 3
Enter time: 0
Exception BadTime called with value 0
Continue doing what you were doing.
$./velocity-exception-classes
Enter distance: 4
Enter time: -1
Exception BadTime called with value -1
Continue doing what you were doing.
try {
throw Exception1();
throw Exception2();
throw ExceptionN();
}
catch(Exception1 e) {
// body
}
catch(Exception2 e) {
// body
}
catch(ExceptionN e) {
// body
}
catch(...) {
// body
}
catch(...)
) statement at
the end of catch statments, otherwise, any catch statement that comes
after a catch-all statement will never get a chance to “catch a thrown
exception”Syntax for catch-all block
is
catch(...) {
}
Example code that shows multiple exceptions being thrown and caught
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class BadTime
{
private:
double t;
;
string n
public:
(double time) : t(time) {
BadTime= "BadTime";
n }
() const { return n; }
string getNamedouble getValue() const { return t; }
};
class ZeroDistance
{};
class NegativeDistance
{};
int main()
{
double d, t;
try {
<< "Enter distance: ";
cout >> d;
cin if (d == 0) throw ZeroDistance();
if (d < 0) throw NegativeDistance();
<< "Enter time: ";
cout >> t;
cin if (t <= 0) throw BadTime(t);
<< "Velocity is: " << d/t << endl;
cout }
catch (BadTime bt)
{
// We explictly name the catch paramter bd, since we plan to use
// it below
<< "Exception " << bt.getName()
cout << " called with value " << bt.getValue()
<< endl;
}
catch (ZeroDistance)
{
// Note we do not mention (name) catch parameter.
// Since we don't plan to use it here.
<< "Exception: ZeroDistance." << endl;
cout }
catch (...)
{
// A catch-all block
//
// Notice that the try-block is throwning a NegativeDistance
// exception that we don't explicitly catch. We
// use this catch-all block to catch any unhandled
// exceptions that may be thrown by the try block.
<< "Exception: an unhandled exception." << endl;
cout }
<< "Program safely continues, once the exception is handeled." << endl;
cout
return 0;
}
Output
$./velocity-multiple-exceptions
Enter distance: 1
Enter time: .2
Velocity is: 5
Program safely continues, once the exception is handeled.
$./velocity-multiple-exceptions
Enter distance: -2
Exception: an unhandled exception.
Program safely continues, once the exception is handeled.
$./velocity-multiple-exceptions
Enter distance: 34
Enter time: 0
Exception BadTime called with value 0
Program safely continues, once the exception is handeled.
$./velocity-multiple-exceptions
Enter distance: 0
Exception: ZeroDistance.
Program safely continues, once the exception is handeled.
E.g.,
class ZeroDistance
{};
It is possible that an exception is thrown in a function, but it is
caught in the calling function try-catch-block. The try-block
seen below, for example, does not contain a throw statement. Here,
function safeDivide
throws the exception
DivideByZero
, but the exception is handled in the
try-catch-block of the calling function.
#include <iostream>
#include <cstdlib>
using std::cin;
using std::cout;
using std::endl;
class DivideByZero
{};
double safeDivide(int top, int bottom) throw (DivideByZero);
int main( )
{
int numerator;
int denominator;
double quotient;
<< "Enter numerator:\n";
cout >> numerator;
cin << "Enter denominator:\n";
cout >> denominator;
cin
try
{
= safeDivide(numerator, denominator);
quotient }
catch(DivideByZero)
{
<< "Error: Division by zero!\n"
cout << "Program aborting.\n";
(0);
exit}
<< numerator << "/" << denominator
cout << " = " << quotient << endl;
<< "End of program.\n";
cout return 0;
}
double safeDivide(int top, int bottom) throw (DivideByZero)
{
if (bottom == 0)
throw DivideByZero( );
return top/static_cast<double>(bottom);
}
This scenario is actually rather common. It makes sense to catch exception in the calling function, since this allows the calling function to react in different ways to the thrown exception. In one situation the calling function may choose to abort the program; where as, in some other situation the calling function may choose to continue.
Consider the two situations below
Situation 1
void allocate_memory() throw OutOfMemory {}
try {
();
allocate_memory}
catch(OutOfMemory) {
// abort
}
Situation 2
void allocate_memory() throw OutOfMemory {}
try {
();
allocate_memory}
catch(OutOfMemory) {
// ask for more memory
}
In the first situation the calling function chose to abort the program; where as, in the second situation the calling function chose to ask for more memory.
Functions, e.g. safeDivide
above, that throw exceptions,
but don’t catch them should warn users that it will throw an exception.
Specifically, such functions should list all exceptions that it
can throw. This is list is often called “exception list” or “throw
list”.
E.g.,
double safeDivide(int top, int bottom) throw (DividebyZero);
or (if more than one)
double safeDivide(int top, int bottom) throw (DividebyZero, SomeOtherException);
The “exception list” or “throw list” should appear in both function’s
declaration and definition.
b If a function throws an exception that was not in its “throw list”,
built-in function unexpected()
is automatically called. The
default behavior of unpected()
function is to terminate the
program. Note that the fact that a function throws an exception that is
not in its throw list does not create a compile-time or run-time error.
Btw. unexpected()
is also called if no try-catch block is
found.
Exception types DividebyZero
or
OtherException
treated normally. All others invoke
unexpected()
.
void someFunction() throw(DividebyZero, OtherException);
Empty exception list, all exceptions invoke `unexpected()
void someFunction() throw ();
All exceptions of all types treated normally
void someFunction();
Polymorphism plays an important role in exceptions. Say class B is derived from class A. If the catch-block handles exception of type class A (i.e., class A is in exception specification) then it will also catch exception of class B is thrown.
E.g.,
class A {};
class B : public A {};
try {
throw B;
}
catch (A)
{
// This block will catch if B is thrown
// in the try block.
}
See the code below for this behavior in action.
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class BadTime
{
private:
double t;
;
string n
public:
(double time) : t(time) {
BadTime= "BadTime";
n }
() const { return n; }
string getNamedouble getValue() const { return t; }
};
class InvalidDistance
{
protected:
;
string name
public:
() {
InvalidDistance= "InvalidDistance";
name }
() const { return name; }
string getName};
class ZeroDistance : public InvalidDistance
{
public:
() : InvalidDistance()
ZeroDistance{
= name + " -> " + "ZeroDistance";
name }
};
class NegativeDistance : public InvalidDistance
{
public:
() : InvalidDistance()
NegativeDistance{
= name + " -> " + "NegativeDistance";
name }
};
int main()
{
double d, t;
try {
<< "Enter distance: ";
cout >> d;
cin if (d == 0) throw ZeroDistance();
if (d < 0) throw NegativeDistance();
<< "Enter time: ";
cout >> t;
cin if (t <= 0) throw BadTime(t);
<< "Velocity is: " << d/t << endl;
cout }
catch (BadTime bt)
{
// We explictly name the catch paramter bd, since we plan to use
// it below
<< "Exception " << bt.getName()
cout << " called with value " << bt.getValue()
<< endl;
}
catch (InvalidDistance id)
{
// Notice that this catch-block catches
// InvalidDistance.
<< "Exception " << id.getName()
cout << " caught." << endl;
}
catch (...)
{
// A catch-all block
//
// Notice that the try-block is throwning a NegativeDistance
// exception that we don't explicitly catch. We
// use this catch-all block to catch any unhandled
// exceptions that may be thrown by the try block.
<< "Exception: an unhandled exception." << endl;
cout }
<< "Program safely continues, once the exception is handeled." << endl;
cout
return 0;
}
Output
$./velocity-exceptions-polymorphism
Enter distance: 2
Enter time: 1
Velocity is: 2
Program safely continues, once the exception is handeled.
$./velocity-exceptions-polymorphism
Enter distance: -2
Exception InvalidDistance -> NegativeDistance caught.
Program safely continues, once the exception is handeled.
$./velocity-exceptions-polymorphism
Enter distance: 0
Exception InvalidDistance -> ZeroDistance caught.
Program safely continues, once the exception is handeled.
Note that ZeroDistance
and NegativeDistance
is not in exception list, but these are caught by
catch(InvalidDistance id)
catch-block, since both
ZeroDistance
and NegativeDistance
are derived
from class InvalidDistance
.
unexpected()
This function is called whenever an unhandled exception is thrown.
The default behavior is to terminate
the program. It is
possible to redifine this function by using set_unexpected
.
I suggest checking out the compiler documentation to the interested
reader.
terminate()
is called,
terminating the programunpected()
is also called if an exception
that is not in the throw list is thrown. This will terminate the
programgoto
statement)rethrow;
to throw the same exception upthrow SomeNewException;
to throw a different
exception to the subsequent catch-blocks