Lab 10 - Exceptions

Examples from Lecture

Example of a program without exception handling (slide 4)

#include <iostream>
using namespace std;
 
//define our exception class
class DivideByZero {};
 
double divide(int a, int b) {
    if(b == 0)
        throw DivideByZero();
    return (double) a / b;
}
 
int main() {
       double d = divide(4, 0);
       cout << d << endl;
}

Example of a program with exception handling using try and catch

#include <iostream>
using namespace std;
 
//define our exception class
class DivideByZero {};
 
double divide(int a, int b) {
    if(b == 0)
        throw DivideByZero();
    return (double) a / b;
}
 
int main() {
    try {
        double d = divide(4, 0);
        cout << d << endl;
    }catch(DivideByZero){
        cerr << "Exception : cannot divide by Zero" << endl;
    }
 
}

What is the difference between the ouput of the two programs? Run both of them and make sure you understand the behaviour.

Using errno - C library example - slides 6 and 7

Note: Save this as a CPP file

#include <cstdio>
#include <cstdlib>
#include <errno.h>
int main() {
    //if error, fopen returns NULL and sets errno
    FILE * f = fopen("filename", "r");
    if (!f) // an error has occurred, check errno
    {
        // file doesn't exist
        if (errno == ENOENT)
            printf("No file\n");
        // perror checks errno and prints message
        perror("An error occurred opening file");
        system("pause");
        exit(-1);         
    }
}

Error handling using signals -

#include <csignal>
#include <cstdio>
#include <cstdlib>
 
void sighandler(int sig)
{
    printf("received signal %d\n", sig);
    exit(-1);
}
int main()
{
    // register the handler with a seg fault
    signal(SIGSEGV, sighandler);
    // do something to cause a seg fault
    delete (int*) -10;
}

Define and using exceptions - slides 12 and 13

#include <iostream>
#include <limits>
using namespace std;
 
struct RangeError {
    int iVal;
    RangeError(int _iVal){iVal = _iVal;}
};
 
char to_char(int i) {
    if (i < numeric_limits<char>::min() || i > numeric_limits<char>::max())
        throw RangeError(i);
    return (char)i;
}
 
void g(int i) {
    try {
        char c = to_char(i);
        cout << i << " is character " << c << endl;
 
    } catch (RangeError re) {
        cerr << "Cannot convert " << re.iVal << " to char\n" << endl;
        cerr << "Range is " << (int) numeric_limits<char>::min();
        cerr << " to " << (int) numeric_limits<char>::max() << endl;
    }
}
 
int main() {
    g(-130);
}

Handling exceptions from a inheritance hierarchy

First handle the specific exception in the catch blocks and then the general exception which should you handled the last

#include <iostream>
using namespace std;
 
class Matherr {};
class OverflowException : public Matherr {};
class UnderflowException : public Matherr {};
class ZeroDivideException : public Matherr {};
 
double divide(int numerator, int denominator) {
    if (denominator == 0) 
        throw ZeroDivideException();
    double d = (double) numerator / denominator;
    return d;    
}
 
int main() {
   try { cout << divide(6,0) << endl; }
   catch (ZeroDivideException) { cerr << "Zero Divide Error" << endl;}
   catch (Matherr) {cerr << "Math Error" << endl;}
   catch (...) {cerr << "Unknown Error" << endl;}
}

Resource management using functions - slide 15

#include <iostream>
using namespace std;
 
void use_file(const char *fn) {
    FILE *f = fopen(fn, "r");
    try {
        // use f
    } catch (...) {
        fclose(f);
        throw;
    }
    fclose(f);
}
 
int main() {
    try {
        use_file("UsingSignalHandling.cpp");
    }catch (...) {
        cerr << "File error " <<endl;
    }
}

Using typeid - slide 19

#include <iostream>
#include <typeinfo>
using namespace std;
 
class Shape {};
 
class Square : public Shape {};
 
class Circle : public Shape {};
 
void f(Shape &r, Shape *p) {
    cout << typeid(r).name() << endl;
    cout << typeid(*p).name() << endl;
    cout << typeid(p).name() << endl; // bug
}
 
int main() {
   Circle c;
   Shape *s = new Square();
   f(c, s);
}

Exercises

Exercise 1 : Defining and using your own exceptions

Write a function calculateAverage() which takes four int arguments which are marks for four courses in the semester and returns their average as a float.
The calculateAverage() function should take only valid range for marks which is between 0 - 100. If the marks are out of range throw an OutOfRangeException - define this exception as a class as shown in the lecture and lecture examples.
Write the specification for this function as comments above it specifying the pre conditions, post conditions and invariants and what exceptions are thrown when so that the caller understand how it behaves.

Solution

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License