Lab09, CISC181h, Spring 2006

Introduction

In this (hopefully) simple lab, you will add some better error-handling capabilities to the Rational_C class that you created in Lab08. Specifically, you will add what are called exceptions.

Thus far in your programming, when an error has occurred (for instance, bad input or something like that), your program has either (1) crashed, or (2) told the user about it and possibly exited. If the error occured inside a function (other than main), then that function had to deal with the error, either by returning an error value, telling the user about the error, or exiting.

But sometimes it is not clear exactly what should be done when an error occurs, especially within code that is reusable. For example, consider your Rational_C class from lab08. An error can occur if a program tries to construct an object with a denominator of zero (since this will not be a rational number). But if such an error occurs, the correct action to take depends on the situation. For example, if the rational number was being constructed based on user input, maybe the program should tell the user and propt for a new, non-zero denominator value. But if the number is being constructed based on some data file, say, then maybe the only thing to do is to exit.

The point is, sometimes we can't know in the context where the exception occurs (i.e. in the function or class definition), what should be done with it. In these cases, it is sometimes a good idea to use C++ exceptions. The function throws an exception and the program that called the function catches it, and then does what it needs to do. This way the function itself doesn't need to know how to handle the error, it just needs to tell its caller that one occurred.

Here's a paragraph from page 795 of Savitch:

Exception handling is commonly used to handle error situations, but perhaps a better way to view exceptions is as a way to handle exceptional situations. After all, if your code correctly handles an "error", then it no longer is an error
In general, Walter Savitch is much better about explaining things than your TA is; that is why he got lots of money to write a book and your TA did not. So you should read chapter 18 in your Savitch textbook.

How exceptions work

First, it is important to keep in mind that an exception can be of any type, from int to Rational_C and everyting in between. To throw an exception, you simply use the operator throw, as follows:

int x = 5;
if( /* some sort of error condition */ ) {
	throw x;
	//or
	throw 5;
}

If you have a function, say foo, that throws an exception, then it should declare that at the beginning of the function prototype and definition, as follows:

// function prototype
int foo(double x, bool y) throw (int);

// ... the rest of your program

// function specification
int foo(double x, bool y) throw (int)
{
	//... the code for the function
	if( /* error condition */ ) throw 5;
}

You can also declare that you might throw multiple types of exceptions, with something like int foo() throw (int,bool,char*);. In this lab, you won't have to deal with this condition, though.

When an exception is thrown, execution stops and goes back up to the caller of the current function. It is up to the caller to catch the exception. You do this with a try-catch block. The way this works is you try to do something which may result in an exception being thrown, and then catch any exception that gets thrown in the try block. If any exception is thrown and not caught, the function terminate() will be called, which by default ends your program. Here's an little fake example of two functions, which each throw one exception, and a main program with tries to call these two functions and catches their exceptions:

#include <csdio>
#include <cstdlib>
using namespace std; // shame on me

//the function prototypes - pretend like they're defined later.
void fun1() throw (int);
void fun2() throw (char);

int main(void) {
	try {
		int x = 5;
		fun1();
		x += 2;
		fun2();
		x += 3;
	}
	catch( int x ) {
		cout << "The function threw this int:" << x <<endl;
	}
	catch( char x ) {
		cout << "The function threw a char" << endl;
		cout << "I'm going to terminate." << endl;
		exit(0);
	}

	return 0;
}

Notice a couple things here. First, you can have anything you want in the try block, including things that will never ever throw an exception (such as x += 3;). Also, in your catch blocks, you have to assign the exception to a variable (in this example, I used x). Then that variable is assigned to the value of whatever was thrown, for the duration of the catch block. Also, make sure you can figure out what the value of x is at the end of the program if fun1 throws an exception, if fun2 throws an exception, and if neither does. If you can't, copy and paste this code, compile it, and find out for yourself.

Getting started—files and directories

The files for this lab are in the lab09 directory. I put a link to this directory at the following location on strauss: ~roche/lab09. See previous labs for examples of how to copy these files into your directory. And remember, of course, to make a new lab09 subdirectory before you get started.

Step-by-Step Instructions

  1. Copy the files into your lab09 directory. Replace the files rational.h and rational.cc with the completed versions you have from lab08.

  2. Add another class to the rational.h file called DenomIsZero. Its entire definition will be:

    class DenomIsZero {};
    This will be the type of the exception you throw. In your functions, to throw an exception of this type, just write throw DenomIsZero(); . See page 811 in Savitch for a great example of this sort of thing.

  3. Look at the code in the file testExceptions.cc. You don't need to do too much to make this test pass, just basically add throw statements to two member functions in rational.cc and in rational.h.

  4. Once your class passes both tests, make a script file where you do a make clean, then make all, then run both tests and show they all pass. Also be sure to cat your rational.h and rational.cc files.

  5. Finishing up and Submitting

    For this lab, you do NOT have to make a tarfile. Just be sure to cat both your source files in your lab09.txt script file, and submit this both on paper and on WebCT.


    Valid XHTML 1.1 Valid CSS!