t e m p o r a l 
 d o o r w a y 

Creating, Throwing and Catching Your Own Custom Exceptions

 

Introduction

The VCL throws a number of its own special exceptions. You can too. But why should you?

First of all, consider the following code:

if (myPointer != NULL)
{
   if (myPointer->Member != NULL)
   {
      myPointer->Member->Something();
   }
   else
   {
      HandleBadPointer();
   }
}
else
{
   HandleBadPointer();
};

and contrast it with...

try
{
   myPointer->Member->Something();
}
catch (EAccessViolation &AccessViolation)
{
   HandlerBadPointer();
};

The bad news is that in the first example, the code that actually does something is buried deep in error prevention code. It's hard to see for all the error preventing code. In the exception-oriented example, the typically executed code is right up front, while the error handling code is more of a footnote.

Now, ideally, it would be nice to be able to use:

try
{
   DoSomething();
   DoSomethingElse();
   DoAThirdThing();
}
catch (ESomethingError &SomethingError)
{
   // handle it
}
catch (ESomethingElseError &SomethingElseError)
{
   // handle it
};

But that would mean you'd need to define your own, application dependent exceptions...

Your Own Exception Classes

There's no problem in defining your own exception classes. You may start from Exception or from a higher level exception like EAccessViolation.

First, I start with a base class for all of my exceptions, which is derived from Exception. This makes it easier to just catch my own defined exceptions if I want, since I don't have to identify them as anything more than that base class. For instance, suppose I call my base class TMCException, then I can

try
{
   // ...
}
catch (TMCException &MCException)
{
   //...
};

to trap any of my exceptions derived from that class. If need be, this could be added to the Project Source to handle special message displays from uncaught exceptions derived from my base class, just as the Project Source currently catches exceptions derived from Exception.

The definitions I use are hidden in #defines:

#define TMCBasicException(EName,Message) \
   class EName: public Exception \
   { \
      public: \
\
         EName(TComponent *theComponent): \
            Exception \
            ( \
               theComponent->Name + \
               String(" - ") + \
               theComponent->ClassName() + \
               String(": ") + \
               Message \
            ) \
         {};\
\
         EName(TComponent *theComponent,String theMessage): \
            Exception \
            ( \
               theComponent->Name + \
               String(" - ") + \
               theComponent->ClassName() + \
               String(": ") + \
               Message + \
               String("; ") + \
               theMessage \
            ) \
         {}; \
   }

#define TMCDerivedException(ParentClass,EName,Message) \
   class EName: public ParentClass \
   { \
      public: \
\
         EName(TComponent *theComponent): \
            ParentClass \
            ( \
               theComponent, \
               theComponent->Name + \
               String(" - ") + \
               theComponent->ClassName() + \
               String(": ") + \
               Message \
            ) \
         {};\
\
         EName(TComponent *theComponent,String theMessage): \
            ParentClass \
            ( \
               theComponent,theComponent->Name + \
               String(" - ") + \
               theComponent->ClassName() + \
               String(": ") + \
               Message + \
               String("; ") + \
               theMessage \
            ) \
      {};\
   }

These look formidable, but what they allow is to define a new exception class with a single line:

TMCBasicException(EBasicException,"Core message describing problem");

The defines qualify that message with information about the name of the component throwing the exception and the name of its class.

Defining Your Own Exception

I strongly recommend that exceptions thrown by a class be defined in that class. For instance:

class TMCNewClass: public TObject
{
   public:
      ...
      TMCBasicException(EUnexpectedError,"An unexpected error occurred.");
}

which is caught with

try
{
   //...
}
catch (TMCNewClass::EUnexpectedError &UnexpectedError)
{
   Application->MessageBox(UnexpectedError.Message.c_str(),"Error",MB_ICONWARNING);
};

Throwing The Exception

Throwing the exception is easy, especially since the defines create a convenient constructor:

throw EUnexpectedError(this,"Something strange happened, so that's additional info");

Despite that your scope folds up after the exception is thrown a statically created exception does not go with it.

The message displayed by the catch in the previous section, by the way, would look something like

MyComponent - TMCNewClass: An unexpected error occurred; Something strange happened, so that's additional info"

What About The Exception Object Storage

The VCL assures us it will dispose of it.

Conclusion

There's a lot more to exception handling than just defining exceptions and catching them. Issues like who catches the exception, who reports them, forwarding the exception as another exception type, and catching exceptions at differing levels of specificity are all important to the mature programmer. But if you pay attention, you will gradually find a useful and controlled organization for exception creation and handling that will make your programs more readable and reliable.

For more on exceptions, have a look at Try and Catch - Error Handling Strategies for C++ Builder.

Copyright © 2004 by Mark Cashman (unless otherwise indicated), All Rights Reserved