Home > Articles > Programming > C/C++

Exception Handling in C++

Stanley B. Lippman
  • PrintPrint
  • Share ThisShare This
  • DiscussDiscuss
Close WindowStanley B. Lippman

Stanley B. LippmanJosée LaJoie

Learn more…

Sorry, this author hasn't written any articles.

Sorry, this author doesn't have anything for sale.

Sorry, this author hasn't posted any blogs.

C++ Primer, 3rd Edition

This chapter is from the book
C++ Primer, 3rd Edition

Learn how to throw an exception, how to associate handlers, or catch clauses, with a set of program statements using a try block, how exceptions are handled by catch clauses, exception specifications, and design considerations for programs that use exceptions.
This chapter features a free online learning environment available at www.codesaw.com.

Exception handling is a mechanism that allows two separately developed program components to communicate when a program anomaly, called an exception, is encountered during the execution of the program. In this chapter we first look at how to raise, or throw, an exception at the location where the program anomaly is encountered. We then look at how to associate handlers, or catch clauses, with a set of program statements using a try block, and we look at how exceptions are handled by catch clauses. We then introduce exception specifications, a mechanism that associates a list of exceptions with a function declaration and that guarantees that the function does not throw any other types of exceptions. We end the chapter with a discussion of design considerations for programs that use exceptions.

11.1 Throwing an Exception

Exceptions are run-time anomalies that a program may detect, such as division by 0, access to an array outside of its bounds, or the exhaustion of the free store memory. Such exceptions exist outside the normal functioning of the program and require immediate handling by the program. The C++ language provides built-in language features to raise and handle exceptions. These language features activate a run-time mechanism used to communicate exceptions between two unrelated (often separately developed) portions of a C++ program.

When an exception is encountered in a C++ program, the portion of the program that detects the exception can communicate that the exception has occurred by raising, or throwing, an exception. To see how exceptions are thrown in C++, let's reimplement the class iStack presented in Section 4.15 to use exceptions to indicate anomalies in the handling of the stack. The definition of the class iStack looks like this:

#include <vector>
class iStack {
public:
   iStack( int capacity )
         : _stack( capacity ), _top( 0 ) { }
   bool pop( int &top_value );
   bool push( int value );

   bool full();
   bool empty();
   void display();

   int size();

private:
   int _top;
   vector< int > _stack;
};

The stack is implemented using a vector of ints. When an iStack object is created, the constructor for iStack creates a vector of ints of the size specified with the initial value. This size is the maximum number of elements the iStack object can contain. The following, for example, creates an iStack object called myStack that can contain as many as 20 values of type int:

iStack myStack(20);

What can go wrong when we manipulate myStack? Here are two anomalies that may be encountered with our iStack class:

  1. A pop() operation is requested and the stack is empty.

  2. A push() operation is requested and the stack is full.

We decide that these anomalies should be communicated to the functions manipulating iStack objects using exceptions. So where do we start?

First, we must define the exceptions that can be thrown. In C++, exceptions are most often implemented using classes. Although classes are fully introduced in Chapter 13, we will define here two simple classes to use as exceptions with our iStack class, and we place these class definitions in the header stackExcp.h:

// stackExcp.h
class popOnEmpty { /* ... */ };
class pushOnFull { /* ... */ };

Chapter 19 discusses exceptions of class type in greater detail and discusses the exception class hierarchy provided by the C++ standard library.

We must then change the definition of the member functions pop() and push() to throw these newly defined exceptions. An exception is thrown using a throw expression. A throw expression looks a great deal like a return statement. A throw expression is composed of the keyword throw followed by an expression whose type is that of the exception thrown. What does the throw expression in pop() look like? Let's try this:

// oops, not quite right
throw popOnEmpty;

Unfortunately, this is not quite right. An exception is an object, and pop() must throw an object of class type. The expression in the throw expression cannot simply be a type. To create an object of class type, we need to call the class constructor. What does a throw expression that invokes a constructor look like? Here is the throw expression in pop():

// expression is a constructor call
throw popOnEmpty();

This throw expression creates an exception object of type popOnEmpty.

Recall that the member functions pop() and push() were defined to return a value of type bool: a true return value indicates that the operation succeeded, and a false return value indicates that it failed. Because exceptions are now used to indicate the failure of the pop() and push() operations, the return values from these functions are now unnecessary. We now define these member functions with a void return type. For example:

class iStack {
public:
   // ...

   // no longer return a value
   void pop( int &value );
   void push( int value );

private:
   // ...
};

The functions that use our iStack class will now assume that everything is fine unless an exception is thrown; they no longer need to test the return value of the member function pop() or push() to see whether the operation succeeds. We will see how to define a function to handle exceptions in the next two sections.

We are now ready to provide the new implementations of iStack's pop() and push() member functions:

#include "stackExcp.h"

void iStack::pop( int &top_value )
{
   if ( empty() )
        throw popOnEmpty();

   top_value = _stack[ --_top ];
   cout << "iStack::pop(): " << top_value << endl;
}

void iStack::push( int value )
{
   cout << "iStack::push( " << value << " )\n";

   if ( full() )
        throw pushOnFull();

  _stack[ _top++ ] = value;
}

Although exceptions are most often objects of class type, a throw expression can throw an object of any type. For example, although it's unusual, the function mathFunc() in the following code sample throws an exception object of enumeration type. This code is valid C++ code:

enum EHstate { noErr, zeroOp, negativeOp, severeError };

int mathFunc( int i ) {
   if ( i == 0 )
        throw zeroOp; // exception of enumeration type

   // otherwise, normal processing continues
}

Exercise 11.1

Which, if any, of the following throw expressions are errors? Why? For the valid throw expressions, indicate the type of the exception thrown.

(a) class exceptionType { };
    throw exceptionType();
(b) int excpObj;
    throw excpObj;
(c) enum mathErr { overflow, underflow, zeroDivide };
    throw zeroDivide();
(d) int *pi = &excpObj;
    throw pi;

Exercise 11.2

The IntArray class defined in Section 2.3 has a member operator function operator[]() that uses assert() to indicate that the index is outside the bounds of the array. Change the definition of operator[]() to instead throw an exception in this situation. Define an exception class to be used as the type of the exception thrown.

  • Share ThisShare This
  • Your Account

Discussions

Make a New Comment

You must log in in order to post a comment.

Related Resources

Danny KalevMinutes from the October 2009 Meeting
By Danny Kalev on November 19, 2009 No Comments

The minutes from the Santa Cruz (October 2009) meeting are available here. Even if you're not a language layer at heart, I encourage you to read them.

Danny KalevA Reader's Opinion on Attributes
By Danny Kalev on October 20, 2009 No Comments

In August I dedicated a series to the debate about C++0x attributes. I believe that it covered the subject in a balanced and detailed way, but I keep getting complaints from C++ users who don't like attributes for various reasons. Here's a recent email I received from a Polish C++ programmer. While it  doesn't represent my opinion about attributes -- I'm rather neutral about this feature and consider it a "solution waiting for a problem" -- but it suggests that attributes are still a highly controversial issue that will haunt C++ for a long time. The email is quoted here with minor edits that and as usual, with all private details removed.

Danny KalevFollowup: The Web 2.0 Guy I Ain't
By Danny Kalev on October 16, 2009 1 Comment

Almost a year ago, I posted here The Web 2.0 Guy I Ain't. People wonder whether I still resist all those Web 2.0 features and technologies at the end of 2009.

See All Related Blogs

Informit Network