CMPT 225 Lab - Exception Handling

 

This lab will cover the basics of handling errors in C++. It uses an amended version of the class from the previous week's lab as an example. Note that this is just a brief introduction to the mechanics of throwing and handling exceptions in C++. If you want to know more this is not a bad place to start.

 

Preliminaries

Make a new project, add a class called ArrayClass and copy and paste the code provided at the end of this document into your ArrayClass .h and .cpp files. This version of the class we looked at in last week's lab has two new methods, get and set, which allow individual array elements to be accessed and changed.

 

The get and set methods will result in errors if the index given to the method is invalid (greater than current size, or less than zero).

 

Exception Handling

There are three components to C++ exception handling, a try block that contains function calls that can throw exceptions, and a catch block that handles those exceptions.

 

Try

The try block is just that, the keyword try followed by a { ... } block that contains a function or functions that might throw errors.

 

Catch

Every try block should be followed by at least one catch block (and often more than one). The catch keyword is followed by ()s which contain the exception type to be handled and a { ... } block which contains the exception handling code.

 

Throw

Functions that throw exceptions contain an if statement that identifies the exception condition. The if block contains a throw expression which consists of the throw keyword followed by a parameter. The parameter is often an exception object, but it could be almost anything including integers or strings.

 

Throwing Exceptions

Let's start by throwing an error in the get method.

 

Get Method

The get method should throw an exception when its index parameter is invalid. Here is the method.

 

int ArrayClass::get(int i)

{

return arr[i];

}

 

First, we need to identify what an illegal index is. The class attributes n and maxSize keep track of the current (number of items in the array) and maximum size of the array. It only makes sense to get elements of the array that have been inserted, that is elements with indexes between 0 and n-1.

 

So, we can insert an if statement to identify the error condition:

 

int ArrayClass::get(int i)

{

if(i < 0 || i >= n) /* throw exception */;

return arr[i];

}

 

The next decision is what exception to throw. As mentioned above this can be pretty much anything. However, we will generally follow the practice of throwing standard exceptions. These are defined in the stdexcept library, so the class needs to have an #include <stdexcept> statement in the header file. This library includes classes that can be used to identify a number of common exceptions. The one we want is the out_of_range exception.

 

The throw clause consists of the keyword throw, and an out_of_range object whose constructor has a string parameter that can be used to identify the exception.

 

int ArrayClass::get(int i)

{

if(i < 0 || i >= n) throw std::out_of_range("get(i) out of range");

return arr[i];

}

 

A throw expression behaves somewhat similarly to a return statement. When a throw expression is reached the function terminates and the value specified in the throw expression is passed to another function (like a returned value). The big difference is that a return statement always returns a value to the preceding function call (on the call stack). A throw statement will bypass any preceding function calls that do not have an appropriate catch statement, so may result in multiple functions being removed from the stack (known as unwinding the stack).

 

Catching Errors

Code (usually function calls) that might cause errors should be enclosed in a try block, and a catch block (or multiple catch blocks) handle those errors.

 

The file below contains a main function and a test function that demonstrates basic exception handling for the get function.

 

ExceptionLab.cpp

 

There are a few things to note about this small test.

The catch block doesn't do anything except report on the error.

The catch block only deals with out_of_range errors. If the code in the try block could throw errors of more than one type it might be appropriate to have multiple catch blocks, where each block handles a different error type.

In this small example, the try and catch blocks are in the function that directly called the method that threw the error. They don't have to be. For example, where function f1 calls f2, which calls f3 which calls f4, and f4 might throw more than one exception type. The catch blocks that deal with these error types could be in any of f1, f2 or f3 (or main), and catch blocks for the different error types can be in different functions.

 

Over to You

Add a throw clause to the set method (it's pretty much identical to the get method), then add some code to the test function to call the methods with some errors. Enclose the method calls in a try block and write catch blocks to print an error message.

 

ArrayClass

 

The class definition and method definitions for the ArrayClass class are provided below.

ArrayClass.h

ArrayClass.cpp

 

 

CMPT 225 Home

 

John Edgar (johnwill@sfu.ca)