CS 250 Computer Programming and Problem Solving - FALL 1998 

[ Home | Syllabus | Notes | Glossary | CS250 WEB Version Home Page | Project Page | Final Study Guide]


Exception Handling

Error handling is a difficult business, particularly if we want to write general purpose objects which can be used in many applications.

Consider an example from test 2 which calculates the average of all values in an array.


long average(LongArray theArray) { 
   long ave = 0; 
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i); 
   }
   return ave/theArray.GetSize(); 
}

What will happen if the array is empty?

How should this be handled. Consider several alternatives.

1. function tests size and if 0 issues error message and then returns

 


long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      cerr << " attempt to divide by 0 in average\n";
      return 0;
   }
   return ave/theArray.GetSize();
}

What do you think of this solution?

2. Try a different solution which aborts on error

long average(LongArray theArray) { 
   long ave = 0;  
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i); 
   }
   assert(theArray.GetSize() != 0); // abort if error possible
   return ave/theArray.GetSize(); 
}

What do you think of this solution?

3. Let the calling program decide what to do.

long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      return DivideZero; // where ErrorValue is a special value
   }
   return ave/theArray.GetSize();
}

4. Return two values - the one we want and an error value.

 


bool average(LongArray theArray, long & theAverage) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      cerr << " attempt to divide by 0 in average\n";
      return false;
   }
   theAverage = ave/theArray.GetSize();
   return true;
}

5. Use structured exceptions.

 


long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      throw -1;
   }
   return ave/theArray.GetSize();
}
// In the calling program
try {
   cout << " the average is " << average(myArray);
}
catch(int error) {
   cerr << " exception:" << error << " occurred - ignoring it.\n";
}

 



long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      throw -1;
   }
   return ave/theArray.GetSize();
}
long middleMan(LongArray someArray){
   return average(someArray);
}
// In the calling program
try {
   cout << " the average is " << middleMan(myArray);
}
catch(int error) {
   cerr << " exception:" << error << " occurred - ignoring it.\n";
}

 


6. Using Exception Classes

 


class DivideByZero{}; // define exception class
long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      throw DivideByZero();
   }
   return ave/theArray.GetSize();
}
// In the calling program
try {
   cout << " the average is " << average(myArray);
}
catch(const DivideByZero& ) { // notice unnamed parameter because not needed
   cerr << " exception: DivideBy Zero occurred - ignoring it.\n";
}

 


7. Handling two exceptions with different catch blocks

 


class DivideByZero{}; // define exception class
long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      throw DivideByZero();
   }
   if(theArray.GetSize() == 1) { // stupid to average one thing
      throw -1;
   }
   return ave/theArray.GetSize();
}
// In the calling program
try {
   cout << " the average is " << average(myArray);
}
catch(const DivideByZero& ) { // notice unnamed parameter because not needed
   cerr << " exception: DivideBy Zero occurred - ignoring it.\n";
}
catch(int) { // don't use the parameter here either
   cerr << " why be so stupid to take the average of one thing!!!\n";
}

8.  Handling two exceptions in different functions

class DivideByZero{}; // define exception class
long average(LongArray theArray) {
   long ave = 0;
   for(int i = 0; i < theArray.GetSize(); i++) {
      ave += theArray.Get(i);
   }
   if(theArray.GetSize() == 0) {
      throw DivideByZero();
   }
   if(theArray.GetSize() == 1) { // stupid to average one thing
      throw -1;
   }
   return ave/theArray.GetSize();
}
long middleMan(LongArray someArray){
   try{
      return average(someArray);
   }
   catch(int) { // don't use the parameter here either
      cerr << " why be so stupid to take the average of one thing!!!\n";
   }
}
// In the calling program
try {
   cout << " the average is " << middleMan(myArray);
}
catch(const DivideByZero& ) { // notice unnamed parameter because not needed
   cerr << " exception: DivideBy Zero occurred - ignoring it.\n";
}

A more sophisticated example demonstrating


// RANGE.H  - RangeError exception class

#ifndef RANGE_H
#define RANGE_H

#include <iostream.h>
#include <string.h>

const unsigned FileNameSize = 40;
// Make this >= longest filename on target system.

class RangeError {
public:
  RangeError( const char * fname,
              unsigned line,
              unsigned subscr )
  {
    strncpy(fileName, fname, FileNameSize);
    lineNumber = line;
    value = subscr;
  }

  friend ostream & operator <<( ostream & os,
         const RangeError & R )
  {
    os << "\nRangeError exception thrown: "
       << R.fileName
       << ", line " << R.lineNumber
       << " value = " << R.value
       << endl;
    return os;
  }

private:
  char fileName[FileNameSize+1];
  unsigned lineNumber;
  unsigned value;
};

#endif

 


// EXCEPT3.CPP - Exception-handling example from Section 8.3.3.

// This program uses a more complete specification for the
// RangeError exception class, simplifying the calling program.

#include <iostream.h>
#include <fstream.h>
#include "fstring.h"
#include "range.h"
#include <stdlib.h>
class MemoryExhausted{};

class LongArray {
public:
  LongArray( unsigned sz = 0 );
  ~LongArray();

  unsigned GetSize() const;

  long Get( unsigned i ) const;

  void Put( unsigned i, long item );

private:
  long * data;   // array of long integers
  unsigned size; // allocation size
};

LongArray::LongArray(unsigned sz)
{
	size = sz;
	data = new long[size];
	if(!data) throw MemoryExhausted();
}
inline LongArray::~LongArray()
{
  delete [] data;
}

inline unsigned LongArray::GetSize() const
{
  return size;
}

inline void LongArray::Put( unsigned i, long item )
{
  if( i >= size )
    throw RangeError( __FILE__ ,__LINE__, i );
  data[i] = item;
}

inline long LongArray::Get( unsigned i ) const
{
  if( i >= size )
    throw RangeError( __FILE__ ,__LINE__, i );
  return data[i];
}

//---------------( test program )--------------------

unsigned GetArraySize()
{
  unsigned n;
  cout << "Number of array elements? ";
  cin >> n;
  return n;
}

// Fill the array with random integers.

void FillArray( LongArray & L )
{
  int i;
  try {
    for( i = 0; i < L.GetSize(); i++ )
      L.Put( i, rand() );
  }
  catch( const RangeError & R ) {
    cout << R;
    throw R;
  }
}

// Retrieve an array element.

void GetArrayElement( const LongArray & L )
{
  int ok = 0;
  while( !ok )
  {
    unsigned i;
    cout << "Enter an array subscript (0-"
         << ( L.GetSize()-1 ) << "): ";
    cin >> i;

    long n;
    try {
      n = L.Get( i );
      ok = 1;
      cout << "Element contains " << n << endl;
    }
    catch( const RangeError & R ) {
      cout << R; hptrd_left.gif (955 bytes)
      cout << "Caught at: " << __FILE__
           << ", line " << __LINE__ << endl;
      throw; hptrd_left.gif (955 bytes)
    }
  }
}


int main()
{
  try {
    LongArray L( GetArraySize() );
    FillArray( L );
    GetArrayElement( L );
  }
  catch( ... ) {
    cout << "Exception caught in main().\n";
    return 1;
  }

  return 0;
}


Copyright chris wild 1998.
For problems or questions regarding this website contact [Chris Wild (e-mail:wild@cs.odu.edu].
Last updated: November 30, 1998.