The Exception Classes


Overview

The classes described in this document are used everywhere in the PolyKit package. They throw an exception when an error occurred.

Why use exception you may ask? Well, it's more easier to make programs, because you don't have to check the return value for each function call you made. Instead you can put all your function calls into a single try block and then catch all errors in one or more catch blocks. Your code will be easier to read and all your error handling code will be in the bottom of your function.

Notice that memory exception can be thrown anywhere, even if it's not documented in a function.


Design

The classes are made using the standard C++ exceptions. There is a class for every kind of exception that can be thrown + one base class all the exceptions classes derives from. The base class is called PException and it handle the basic stuff with the exceptions. All the functions and variables this class have, are also available from the other exceptions classes.


How to use the exceptions

Exceptions must be used in all programs using the PolyKit classes. Since all the classes use exceptions, it is not possible to skip this requirement for even the simplest program.

To use exceptions, you have to use the standard C++ keywords. This chapter will help you to use the C++ keywords and to
understand how to use them in our structured error handling.

The C++ standard has these keywords:

try
catch(x)
catch(...)
throw
throw x

If you want to catch exceptions, you have to create a try block with the try keyword. When an exception is thrown inside your try block, a catch handler will catch it. If you don't have a catch handler for the exception that got thrown, an outer try block will catch it. If it can't find any try block that can catch the exception, your program will be terminated, which is not a good
thing. Here is an example of a simple try block:

          try
          {
           ....
          }
          catch(...)
          {
           ....
          }

Now let's see how to create a double try block, so you can see how C++ locates the right catch handler to call:

          try
          {
           try
           {
            ....
            throw 42; // It's the catch(int) that gets called
           }
           catch (char *str)
           {
            ....
           }
          }
          catch(int)
          {
           ....
          }

The catch(...) will catch all exceptions. This can be used if you want to catch all kinds of exceptions, clean up a little bit and re-throw it. Let's take another example:

          try
          {
           char *str = new char[100];

           try
           {
            ....
            throw 42;
           }
           catch (...)
           {
            delete[] str;
            throw;
           }
          }
          catch(int)
          {
           ....
          }

In your catch handler, you also need to make a try block, which will catch all exceptions. This is necessary, if your code in the catch block might throw an exception. The new catch handler should just make a call to the PlayBeep() function. Here is an example:

           ....
           catch(...)
           {
            try
            {
             ....
            }
            catch(...)
            {
             PlayBeep();
            }
           }

PolyKit exceptions

PolyKit can and will throw exceptions. The PolyKit exception is caught with a PException class. This is because all PolyKit exceptions are derived from the PException class. You can of course catch the other PolyKit exception directly, just remember they have to be before the PException catch handler. Here's another example:

          try
          {
           ....
          }
          catch(PFileException e)
          {
           ....
          }
          catch(PUserException e)
          {
           ....
          }
          catch(PException e)
          {
           ....
          }
          catch(...)
          {
           ....
          }

Notice that the PolyKit catch handler gets passed the exception by value. This is the only legal way to catch PolyKit exceptions.

When you need to throw an exception, you just use the throw C++ keyword. As the argument to this keyword, you give a just created exception object. Here's some examples:

          throw PMemoryException();

          throw PFileException(P_FILE_ERR_ENTRY_NOT_FOUND, "myfile.txt");

Structured error handling

We have designed a structured error handling mechanism you have to obey, except if you have a really good reason not to. First are here some rules you have to follow:

These rules are very important. Let's take an example to show you how to use these rules. Let's say you have an Open File function in your program. You want to open the file the user give you and read some information from it. To do that, you
have created some functions.

          void OpenDocument(void)
          {
           try
           {
            ....
            OpenFile();
            ....
           }
           catch(PMemoryException e) // Last chance memory catch handler
           {
            // Show memory error to the user
            ....
           }
           catch(...) // Last chance catch handler
           {
            ....
           }
          }

          void OpenFile(void)
          {
           try
           {
            AskForFilename();
            ReadFile();
           }
           catch(PFileException e)
           {
            // Show error to the user
            ....
           }
          }

          void ReadFile(void)
          {
           openTheFile();

           try
           {
            ....
           }
           catch(...)
           {
            closeTheFile();
            throw;
           }

           closeTheFile();
          }

Now we take the above example step by step. In the main function, we have our "last chance" catch handler. This is the catch handler which job is to catch all the exception we don't catch by ourselves. By "last chance" I mean you have to catch all exceptions so your program won't crash. In real projects, you probably need to put these try blocks several places, e.g. in the initialize and exit functions.

Notice that I also catch the PMemoryException. The reason I do this is to show a message to the user, that there are memory problems. An example of a memory problem is, if you want to read a big file into the memory at once and there isn't enough memory to allocate memory for the whole file.

The OpenFile() function opens the file and read from it. All these functions are stored in one try block, which will catch all file exception. If we got one of these, we show the error to the user. This is the right place to show the error, because it's the last place the exception will visit.

The ReadFile() function catches all exceptions, clean up a little bit and throw it again. This is one of the common uses of exceptions. There are a lot of examples where you need to do this. You can e.g. have allocated some memory and when an error occur, you need to free the memory again.

What I have tried to explain above, are the methods you have to use when you use exceptions in your projects. You have to obey them, even in small programs. Then we are sure our programs are more stable than Microsofts ;^)


PException

Derived from: None

Declared in: PException.h


PException Constructor and Destructor


PException()

          PException(int32 error = P_ERR_ANY);

Initialize the exception object and store the error code in the object.


~PException()

          virtual ~PException(void);

Does nothing.


PException Member Variables


errorNum

          int32 errorNum;

Here is stored the error number you give in the constructor. This variable is always present in all the other exception classes too.


PBoundsException

Derived from: PException

Declared in: PException.h


PBoundsException Constructor and Destructor


PBoundsException()

          PBoundsException(int32 error = P_ERR_ANY, double val = 0.0);

Calls the base class constructor and initialize the class with the value given. This value should indicate the value that was out-of-range.


~PBoundsException()

         virtual ~PBoundsException(void);

Does nothing.


PBoundsException Member Variables


value

          double value;

This variable hold the number that caused the exception to be thrown.


PFileException

Derived from: PException

Declared in: PException.h


PFileException Constructor and Destructor


PFileException()

          PFileException(int32 error = P_FILE_ERR_FILE, PString file = "");

Calls the base class constructor and initialize the class with the filename given.


~PFileException()

         virtual ~PFileException(void);

Does nothing.


PFileException Member Variables


fileName

          PString fileName;

This variable hold the filename to the file which the error occurred on.


PKeyException

Derived from: PException

Declared in: PException.h


PKeyException Constructor and Destructor


PKeyException()

          PKeyException(int32 error = P_ERR_ANY);

Just calls the base class constructor.


~PKeyException()

          virtual ~PKeyException(void);

Does nothing.


PMemoryException

Derived from: PException

Declared in: PException.h


PMemoryException Constructor and Destructor


PMemoryException()

          PMemoryException(int32 error = P_GEN_ERR_NO_MEMORY);

Just calls the base class constructor.


~PMemoryException()

          virtual ~PMemoryException(void);

Does nothing.


PResourceException

Derived from: PException

Declared in: PException.h


PResourceException Constructor and Destructor


PResourceException()

          PResourceException(int32 error = P_GEN_ERR_NO_RESOURCES);

Just calls the base class constructor.


~PResourceException()

          virtual ~PResourceException(void);

Does nothing.


PSoundException

Derived from: PException

Declared in: PException.h


PSoundException Constructor and Destructor


PSoundException()

          PSoundException(int32 error = P_ERR_ANY);

Just calls the base class constructor.


~PSoundException()

         virtual ~PSoundException(void);

Does nothing.


PSystemException

Derived from: PException

Declared in: PException.h


PSystemException Constructor and Destructor


PSoundException()

          PSystemException(int32 error = P_ERR_ANY);

Just calls the base class constructor.


~PSystemException()

         virtual ~PSystemException(void);

Does nothing.


PUserException

Derived from: PException

Declared in: PException.h


PUserException Constructor and Destructor


PUserException()

          PUserException(int32 error = P_OK);

Just calls the base class constructor.


~PUserException()

          virtual ~PUserException(void);

Does nothing.


The PolyKit developer documentation.
This documentation was written by Thomas Neumann.
&COPY Copyright 1998-1999 by PolyCode.