You are on page 1of 16

"icoansi ALIGNleft> Exception handling explained in this section is a new feature

introduced by ANSI-C++ standard. If you use a C++ compiler that is not adapted to this
standard it is possible that you cannot use this feature.

During the development of a program, there may be some cases where


we do not have the certainty that a piece of the code is going to work
right, either because it accesses resources that do not exist or because
it gets out of an expected range, etc...

These types of anomalous situations are included in what we consider


exceptions and C++ has recently incorporated three new operators to
help us handle these situations: try, throw and catch.

Their form of use is the following: try { // code to be tried throw exception; }
catch (type exception) { // code to be executed in case of exception }

And its operation:


- The code within the try block is executed normally. In case that an exception takes
place, this code must use the throw keyword and a parameter to throw an exception. The
type of the parameter details the exception and can be of any valid type.
- If an exception has taken place, that is to say, if it has executed a throw instruction
within the try block, the catch block is executed receiving as parameter the exception
passed by throw.

For example:

// exceptions include <iostream.h int main Exception: Out of range


() { char myarray[10]; try { for (int n=0;
n<=10; n++) { if (n9) throw "Out of
range; myarray[n]='z'; } } catch (char *
str) { cout << "Exception: << str << endl;
} return 0; }

In this example, if within the n loop, n gets to be more than 9 an


exception is thrown, since myarray[n] would in that case point to a non-
trustworthy memory address. When throw is executed, the try block
finalizes right away and every object created within the try block is
destroyed. After that, the control is passed to the corresponding catch
block (that is only executed in these cases). Finally the program
continues right after the catch block, in this case: return 0;.

The syntax used by throw is similar to that of return: Only the


parameter does not need to be enclosed between parenthesis.

The catch block must go right after the try block without including any
code line between them. The parameter that catch accepts can be of
any valid type. Even more, catch can be overloaded so that it can
accept different types as parameters. In that case the catch block
executed is the one that matches the type of the exception sent (the
parameter of throw):

// exceptions: multiple catch blocks include Exception: index 10 is out of range


<iostream.h int main () { try { char *
mystring; mystring = new char [10]; if
(mystring == NULL) throw "Allocation
failure; for (int n=0; n<=100; n++) { if
(n9) throw n; mystring[n]='z'; } } catch
(int i) { cout << "Exception: ; cout << <<
i << is out of range<< endl; } catch (char
* str) { cout << "Exception: << str <<
endl; } return 0; }

In this case there is a possibility that at least two different exceptions


could happen:

1. That the required block of 10 characters cannot be assigned (something rare, but
possible): in this case an exception is thrown that will be caught by catch (char
* str).
2. That the maximum index for mystring is exceeded: in this case the exception
thrown will be caught by catch (int i), since the parameter is an integer number.

We can also define a catch block that captures all the exceptions
independently of the type used in the call to throw. For that we have to
write three points instead of the parameter type and name accepted
by catch: try { // code here } catch (...) { cout << "Exception occurred; }

It is also possible to nest try-catch blocks within more external try


blocks. In these cases, we have the possibility that an internal catch
block forwards the exception received to the external level, for that the
expression throw; with no arguments is used. For example: try { try { //
code here } catch (int n) { throw; } } catch (...) { cout << "Exception occurred; }

Exceptions not caught

If an exception is not caught by any catch statement because there is no catch statement
with a matching type, the special function terminate will be called.

This function is generally defined so that it terminates the current


process immediately showing an "Abnormal terminationerror message.
Its format is: void terminate();

Standard exceptions
Some functions of the standard C++ language library send exceptions that can be
captured if we include them within a try block. These exceptions are sent with a class
derived from std::exception as type. This class (std::exception) is defined in the C++
standard header file <exception and serves as a pattern for the standard hierarchy of
exceptions:
exception
"16linea2 =16 =16 ALIGNleft>bad_alloc (thrown by new)
(thrown by dynamic_cast when
"16linea2 =16 =16 ALIGNleft>bad_cast fails with a referenced type)
(thrown when an exception
"16linea2 =16 =16 ALIGNleft>bad_exception doesn't match any catch)
"16linea2 =16 =16 ALIGNleft>bad_typeid (thrown by typeid)
"16linea2 =16 =16 ALIGNleft>logic_error
"16linea1 =16 =16 ALIGNleft>"16linea2 =16 =16
ALIGNleft>domain_error
"16linea1 =16 =16 ALIGNleft>"16linea2 =16 =16
ALIGNleft>invalid_argument
"16linea1 =16 =16 ALIGNleft>"16linea2 =16 =16
ALIGNleft>length_error
"16linea1 =16 =16 ALIGNleft>"16linea3 =16 =16
ALIGNleft>out_of_range
"16linea2 =16 =16 ALIGNleft>runtime_error
"16linea1 =16 =16 ALIGNleft>"16linea2 =16 =16
ALIGNleft>overflow_error
"16linea1 =16 =16 ALIGNleft>"16linea2 =16 =16
ALIGNleft>range_error
"16linea1 =16 =16 ALIGNleft>"16linea3 =16 =16
ALIGNleft>underflow_error
"16linea3 =16 =16 ALIGNleft>ios_base::failure (thrown by ios::clear)
Because this is a class hierarchy, if you include a catch block to capture any of the
exceptions of this hierarchy using the argument by reference (i.e. adding an ampersand &
after the type) you will also capture all the derived ones (rules of inheritance in C++).

The following example catches an exception of type bad_typeid


(derived from exception) that is generated when requesting information
about the type pointed by a null pointer:

// standard exceptions include <iostream.h Exception: Attempted typeid of NULL


include <exception include <typeinfo pointer
class A {virtual f() {}; }; int main () { try {
A * a = NULL; typeid (*a); } catch
(std::exception& e) { cout << "Exception:
<< e.what(); } return 0; }

You can use the classes of standard hierarchy of exceptions to throw


your exceptions or derive new classes from them.
Understanding C++ Exception Handling
by Steve Crocker

Introduction
Exceptions have been around in C++ for a while and are pretty
common. If you use the STL or even just new you have been exposed to
exceptions. Of course, like all things in C++, having a language feature
does not necessarily clearly point one in the direction of the best use of
that feature. I would not dare to call myself an expert or authority on
exception handling, but as a user of C++ I've had some exposure to
using exceptions.

This article will offer some insight into the use and potential misuse of
exceptions. I highly recommend reading Scott Meyer's More Effective
C++; there is a whole section devoted to exceptions. Bjarne
Stroustrup's The C++ Programming Language Third Edition also has
some excellent information on exceptions. I am assuming that the
reader is familiar with the basics of exception handling and hopefully
has read over Meyer's items on exceptions.

I also use a few terms from John Lakos's Large Scale C++ Software
Design. This book is invaluable for understanding how a logical design
should be translated into a collection of namespaces, header files,
source files and libraries. I mostly refer to components and packages.

Overview of C++ Exception Handling


C++ Exception Handling is centered around the three keywords: try,
catch, and throw, the general purpose of which is to attempt to execute
code and handle unexpected exceptional conditions, hence the name.
This consists of utilizing a try block (with its attendant handlers). Here's
a simple code snippet that should look familiar:

try
{
if ( ! resourceAvail )
throw MyExceptionClass( "Resource Is Not Available" );
}
catch(MyExceptionClass& myException)
{
// resource was not available, do something cleanup

throw;
}
The code checks to see if a resource is available and if not, throws an
exception. The handler for the MyExceptionClass presumably does
something meaningful about the exceptional state. From this over-
simplified example we can see a typical use of exceptions which is to
prevent continued operation if the program cannot obtain the required
resource. Another example of this use of exceptions is new(), which will
throw the standard exception bad_alloc if the required amount of
memory is not available. (Unless, of course, you've changed the new
handler.)

Implications of Using Exceptions


To support exceptions and stack-unwinding, the process of calling
destructors on leaving a scope, compilers put in some initialization
code to ensure that if a routine may return via an exception it will
properly call destructors. This seems to imply that stack-unwinding is a
big part of the fixed cost regardless of whether or not you use a
try/catch block. Even if you only use primitive types, if you make calls
to functions, which is highly likely, then you probably end up paying
this cost. So it is probably best to assume that this fixed cost is a part
of the cost of a function call, and potentially, scope change if that
scope change has local variables.

This means there is additional code being executed. This can consist of
function calls that the compiler automatically inserts into the code.
Some compilers may allow this code to be generated inline to improve
performance, such as C++ Builder. So if we are probably going to be
paying this cost, then why worry about how many try/catch blocks
there are? Because it is best to partition error handling code from
regular execution code. This keeps the intent of the code clear.

Another important fact about exceptions is that they affect program


flow control. This is very significant particularly during the debugging
process. A thrown exception can transfer control to a catch in a very
distant location as well as, of course all the way up to main(). This can
wreak havoc with figuring out the origin of the exception. Just consider
this innocuous source listing:

try
{
SomeFunc();

AnotherFunc( 16 );

YetAnotherFunc( EvenMoreFunctions( 2 ) );
}
catch(...)
{
// catch all exceptions and cleanup

throw;
}

Now try debugging this when an exception is generated by a function


that EvenMoreFunctions() calls. And it only happens some of the time.
Granted, if you're in a debugger you can just enable the 'Break on C++
Exception' option and viola. However, if this a bug report from a tester,
or worse, customer, and it rarely happens, well then you have some
trouble.

It is not just the throw of an exception which impacts program flow


control. The catch clause or more specifically, clauses can have a
significant effect as well. When the exception is thrown it will be
transferred to the first matching catch block of the exception type
thrown. This can be conceptualized as a special kind of switch
statement; and a switch statement affects flow control.

Exception Specifications
When I first started learning about exception specifications I flip-
flopped quite a bit about how useful they are. I could see the benefits
from a client perspective, but the implications imposed on the
component writer made me reconsider where exactly they should be
applied.

The essential benefit of an exception specification is that clients of a


component know exactly what exceptions may be thrown from a
function or a method. This can be great from the client perspective of
handling exceptions, because the client knows exactly what
exceptions, if any, may be thrown. However, as a component
implementer, the cost of guaranteeing meeting that expectation may
be high.

For example, let's consider the following code.

class MyClass
{
void MyMethodWithOnlyOneExceptionSpecification(void)
throw (MyExceptionClass);
void MyMethodThatThrowsNoExceptions(void) throw();
};
As a client of MyClass you can say, "Great! I only have to worry about
MyExceptionClass exceptions coming out of
MyMethodWithOnlyOneExceptionSpecification() and no exceptions will
be thrown from MyMethodWithThrowsNoExceptions()."

In actuality, the first exception specification says that exceptions of


type MyExceptionClass or derived from MyExceptionClass may be
thrown from that method. But maybe that isn't such a big deal after all.
As a client you may only care about the generic MyExceptionClass.

However, to implement this specification we will most likely have to


use a try/catch block within the implementation of these methods to
enforce the exception specification. Otherwise we run the risk of
std::unexpected() being called, the default behavior of which is to
terminate the application. Clients of our class may override this default
behavior, but as a component implementer we cannot make this
assumption. And since aborting the program execution is usually much
more catastrophic than letting an exception propagate all the way up
we have to fall back on using the try block. This means you could be
imposing performance penalty for your exception specification, above
and beyond the performance penalty of the exception specification,
that is. Granted, maybe you could conditionally compile the try block in
debug versions of your component and or package, but that seems
rather dangerous.

Because of this problem, it seems best to avoid exception


specifications for most components. So where does it make sense to
use exception specifications? My experience has indicated that if you
need to enforce an exception specification, either of a specific
exception class or no exceptions, then you should probably do so at
the highest level components of your package. And do so only when
you know you must. Another potential location for using exception
specifications is in thread routines as throwing an exception out of a
thread routine is analogous to throwing one out of main().

Real-time systems, such as games, may benefit from not permitting


exceptions to be thrown from certain portions of their API. This is
because of the effect on flow control exceptions have. In this case it
may be beneficial to use exception specifications to enforce this.

Designing With Exceptions


When implementing the packages which make up your application,
such as your core graphics engine, it is very useful to define an
exception hierarchy to utilize. This is useful for delineating kinds of
exceptions as well as translating error codes into useful string
messages. An example of this is the standard exceptions of the
Standard C++ Library.

A simple base class exception type can contain an error message


string into which you can place your exception information. Specifying
constructors which take parameters that specify the file and line
number ( which typically can obtained from __FILE__ and __LINE__ ) and
a string message allows for an easy way of storing the origin of the
exception. You can also put a simple method for logging the exception
which can be called in the constructor of a concrete exception class.

I've also defined exception classes which translate DirectX error codes
into a human readable message. If a component in the game engine
package throws an exception it is always of a type derived from the
base exception class of the package.

In general, if you are going to throw an exception, you might as well


gather up as much knowledge about the exception then because you
are already paying a huge performance penalty for throwing the
exception. Also, if the act of throwing your exception happens to cause
memory exhaustion, there is guaranteed to be enough memory free to
throw a bad_alloc exception. My experience has been that you'll likely
get terminated by the operating system before bad_alloc is thrown,
however in either case you're already in a world of hurt.

I'll admit that I've opted-out of using exception specifications in my


DirectX wrapper package in order to avoid adding superfluous try
blocks.

Also, since the exception classes themselves log the error message I
can make my catch blocks either catch-all handlers or for my base
exception class and still log exception information automatically. It is
probably best to use the specific handler in places where only your
own exception classes will be thrown and use the catch-all when
making calls into APIs which may be throwing anything; this second
case includes calling new() and its potential throw of bad_alloc. And I
generally have one catch handler for the try block in order to simplify
program flow control.

"Resource allocation is initialization" or


Stack-Based Resource Management
This technique, as described Margaret A. Ellis and Bjarne Stroustrup in
The Annotated C++ Reference Manual, by Stroustrup in The C++
Programming Language Third Edition and further elaborated on by
Meyers in More Effective C++ is well documented. I usually prefer to
think of it as Stack-Based Resource Management because it tells me a
little more about what is going on and what the goal is.

A great example of this is the Standard C++ Library's auto_ptr()


template class, which is specifically designed for this purpose. Here's
an example of how it is typically used:

void Func(void)
{
auto_ptr myClass( new MyClass( ... parameters ... ) );

myClass->Something();
}

There is a number of cool things about this simple example. First, we


don't have to worry about deleting the heap object in the case of an
exception or normal execution; the auto_ptr's destructor handles this
for us. This also means we have one path of execution regardless of
whether or not any exceptions occur; either memory exhaustion or
those thrown by the constructor of the class. This solution also scales
well to having many heap allocated local objects. Even better, we do
not have a try block! So we've already simplified the code significantly.

By using a different kind of smart pointer ( auto_ptr does not


necessarily have the best copy semantics for this ) we can also apply
this technique to classes which have multiple heap objects as
members. This way we can properly handle construction without
memory leaks and without a try block. Granted, maybe allocating
multiple heap objects is going to cost more in terms of time than the
try block initialization is, so maybe its a bit unnecessary from a
performance standpoint, but it does make the constructor less
cluttered.

Another common use of this technique is for synchronization


mechanisms such as critical sections. If a portion of code or an entire
routine needs to be synchronized, a simple object can be used to enter
the critical section in the constructor and leave the critical section on
destruction. I've seen this referred to as a guard or lock.

The fundamental is what Meyer's succinctly describes in More Effective


C++ Item 9 - use destructors to prevent resource leaks. I usually tend
to think of it as putting code which must execute, regardless of how a
block is exited, into the destructor of an object on the stack. In auto_ptr
the resource is memory, in a critical section the resource is the lock on
the critical section. No doubt you can think of other examples which
may be more involved than these simple examples.

This is really one of the most useful aspects of exception handling:


stack unwinding. And not only does it make the code easier to read
and understand it also can be used to eliminate try blocks, which can
help improving application performance.

Interactions with Threads


There are a few important things to keep in mind when dealing with
exceptions in a multi-threaded program. Most are pretty
straightforward but if forgotten can cause a number of problems.

First is that each thread routine is akin to main() and you should not
allow exceptions to be thrown out of the thread routine. Provided you
created the thread using _beginthread(), and properly initialized the
runtime library, your application will exit indicating abnormal program
termination. Otherwise you will likely cause the operating system to
display an unsightly message about your application and offer to
terminate it for you. This is actually worse than throwing an exception
from main() which should just indicates abnormal program
termination.

Trying to use an exception specification on the thread routine in order


to get it to call your installed unexpected handler does not seem to
work. The application just terminates executes as if no exception
specification existed. I'm not sure if this is considered a bug in my
compiler or not. The bottom line is that each thread routine should be
created using _beginthread() and include a try-block and a catch-all
handler just like main() generally does.

Next is that each thread routine has its own stack, and hence
exception chain. This means that the current exception has to be per
thread data and re-throwing an exception is, obviously, only valid
within a single thread. The implication is if you have multiple threads
which may be working with the same component or group of
components and one causes an object to enter an invalid state due to
an exceptional condition, your other threads will probably not be aware
of this, even if you are properly synchronizing access.

The problem is that an exceptional condition in one thread has no way


of indicating to another thread that such a condition has occurred. And
when your other thread is scheduled it will probably end up
encountering an exception as well. This means that an exception in
one thread should probably stop the other related threads as well. Of
course, subtle problems can arise in how those other threads are
stopped. I've usually used an approach where one thread, maybe the
main application thread, is ultimately responsible for stopping the
dependent threads if one of them stops running. It may also be
responsible for stopping other threads and itself if one of the threads it
is dependent upon stops running. I've also generally taken the
approach that exceptions should get propagated up to the thread
routine and should cause the thread to exit, in a normal fashion, which
would then allow the managing thread to notice one thread it is
dependent upon is not running and shut down all relevant threads.

Exceptions in Real-Time Systems


Real-Time systems may be a bit of an overloaded term, but it is
applicable to games. After all, what is a computer game other than a
software-based real-time system? Otherwise, why would we complain
about low frame rates?

My experience, however limited, with game programming and other


real-time systems have led me to my current belief that real-time
systems should not throw exceptions out to their clients. By this I mean
a high level component, perhaps the main package interface, which
may have a number of sub-components which make up the real-time
system. These sub-components, particularly if well insulated from
clients can throw exceptions to their heart's content, but the main
engine control interface probably should not. Under what would be
exceptional conditions it should shut down and indicate such an error
condition to the client. It is fine if the client of that engine then used
that error code to throw an exception based on it, but that decision has
been pushed into application level code. This makes the engine more
flexible for clients.

One problem with throwing exceptions is that there may be other real-
time systems which are running concurrently and interdependently.
This may cause one of them to not stop properly. Not to mention the
issues involved with stopping a real-time system cleanly, particularly a
multi-threaded one.

Exception Handling Philosophies


The fundamental reason for throwing an exception is to stop program
execution along the current path. This generally means an error
condition has occurred and normal program flow cannot continue. The
best benefit to this is that client code can be simplified and yet still
allows the implementer of a component to guarantee that if an error
occurs the client will be aware of it. Basically, it removes the
responsibility of a client to check error codes.

There seem to be three common reasons for throwing an exception:

1. A programming error - a pointer is null when it should not be


2. A resource is not available for acquisition or release - bad_alloc on memory
exhaustion
3. A violation of a class invariant or a state of an object invariant - such as an
invalid parameter is passed to a method or a calculation that goes out of
range

So the reasons to throw an exception seem pretty straightforward. The


more difficult question is where to handle exceptions. This is can be a
lot more complicated an issue because of the flow control aspect of
exceptions. We have to look at what most try/catch blocks are trying to
accomplish.

Generally, I've seen try/catch blocks trying to do a few different things:

1. Prevent resource leaks


2. Stop an operation after it has failed
3. Stop an operation deciding how to continue based on the cause of the error

As we've seen from "Resource allocation is initialization" the first use of


a try/catch block is completely unnecessary. We can eliminate the need
for the try block, improving the clarity of the code, by using auto_ptr
and similar classes to handle the releasing of resources in their
destructors. This can also work for thread synchronization objects ( at
least ones which you are not going to timeout on, such as a critical
section ) and can be applied to other forms of resource acquisition. So,
we can easily, relatively speaking, remove the try/catch blocks which
are only preventing resource leaks and improve program performance
and clarity.

The second use of a try/catch block is probably the most coherent use
of exception handling. At some level in the system we attempt to
perform a, usually, complex task which may fail in a number of ways.
In this use of a try/catch block we are only concerned with complete
success. No matter what the failure is we handle it in the exact same
manner. Informing the user of the cause of the error can still be
handled in a generic way, particularly if you have your own exception
hierarchy. Your base class of your exceptions can provide a method for
translating an exception into a human readable message that can be
presented to the user. This allows the user to know why the operation
failed and yet keeps the flow control simple in the error handler case.

The last example of exception handling seems at first like a simple


permutation on the second one, but there are number of consequences
involved. Having more than one catch block amounts is a form of
branching and introduces more complex flow control. There are
instances where this is unavoidable but hopefully you can minimize
them. Maybe you handle only a few specific exceptions and the others
are not handled. Perhaps these are from an unrelated exception
hierarchy or you must handle specific exception classes in unique
ways.

The critical question to consider is whether or not the system is


handling the exception at the given location. Handling the exception
can usually be read as not re-throwing it. If you are re-throwing an
exception then you're not really handling it, you're just trying to return
your object or system to a valid state. And if you find yourself having
to do this in a number of different ways depending upon the exception
thrown then you are potentially creating future maintenance problems.
The reason for this is that it implies that proper error handling follows a
chain of exception handlers that are spread across different levels of
the system.

To minimize this complexity you should let the exceptions go up to the


highest level possible in the system, usually the point at which the
application, or highest level components of the package, initiated the
operation.

Similarly, a thrown exception should always propagate outside of the


function which generated the exception. They should also usually
propagate out of the component which generated them. This follows
the idea that exceptions are a non local form of error handling. If you
throw an exception in within a function and handle it directly in that
function then it is being used as a form of flow control and can obscure
that flow.

Potential Pitfalls
Having run into a number of pitfalls in using exception handling, I'd like
to offer some things to watch out for. Mainly these focus around
understanding the system at run time and conceptualizing program
flow control.
Knowing when to re-throw an exception and when not to can
sometimes be difficult. It is far better to err on the side of caution and
always re-throw the exception unless you are a thread routine or high-
level component controlling a real-time system. This is at odds with
deciding whether or not you are handling an exception and are not re-
throwing it. The issue really hinges on the organization of your
components and the level in the system at which they exist. Generally
this means the top level components in the package or application
should have most of the exception handlers.

The reason being is that if you do not re-throw the exception you are
potentially introducing complex flow control that is not apparent when
inspecting the code. Although using the technique of logging each
exception on its construction can help alleviate this somewhat. This
tends to indicate that you should minimize exception handlers in low-
level components, using them only for freeing resources. When used
this way, they can be replaced with objects on the stack which perform
this resource management automatically.

Also, if you find yourself writing duplicate cleanup code in an exception


handler and the regular function body, particularly if this is a catch(...)
handler, it can made clearer using the such techniques as applying
auto_ptr. Whenever this duplicate code exists it indicates such code is
intended to execute under any condition of exit of the current scope;
such as a destructor call for local objects on the stack.

A more thorny issue has to do with using multiple catch handlers for
different types of exceptions. It is important to remember that each
catch handler is a separate branch of execution. If you find yourself
doing different things based upon the type of exception you catch you
are walking down a potentially dangerous path. Basically, this amounts
to two bad things, one is case analysis of object type, generally
considered bad and using exceptions as a form of messaging.

The problem with case analysis is similar to other problems with case
analysis. If a new exception object is introduced into the system it may
need to have its own handler added and address the new 'case' of
exception. Even worse is that if the catch handlers do radically
different things then the application's behavior becomes dependent
upon what exception it catches. This leads us into the second problem.

Since the program behavior is being guided by the type of exception


caught a particular location you can get unexpected behavior caused
by a different origin point of the exception. If the same exception is
thrown from a different location in code that is called within the try
block with the switch statement like catch handlers, then the program
flow control will transfer to that handler for a different reason. This new
reason may be just different enough from the origin set of assumptions
that it causes subtle bugs. This can be particularly troublesome if this
occurs in a low-level component that may not be accessible to the
client.

Basically unless you write and maintain all the code that your try block
executes you cannot safely make assumptions about the origin of an
exception. Even if you do, the components are likely to be in different
locations and their flow control interactions will not be immediately
apparent. This can create a kind of pseudo-event handler mechanism
and the problem, in this context, with the event handler model is you
do not know the origin of the event, only the occurrence of it. It is far
safer to assume that you have no idea what specific exceptions may be
thrown from where, unless exception specifications are present, but
there's that whole can of worms.

Unfortunately, oftentimes this form of exception type analysis is


exactly the only viable solution. The thing to try to keep in mind is to
avoid this as much as possible. And it can be mitigated a bit by trying
to have those specific exception handlers at the highest level of
organization possible. This is also true of re-throwing exceptions as
well; let them bubble up as far as possible.

Conclusion
Exception handling is obviously a powerful feature of the C++
language. Although you can walk down the path of not using
exceptions at al, their benefits far outweigh the costs. The key is to
understand how exceptions operate; how they interact in a game
application or other real-time system; where to use them and not use
them; and to understand their effect on performance. Exceptions can
greatly simplify the development of a C++ package and provide the
component writer a way to enforce the assumptions made when the
component was implemented.

I would be glad to hear of other's experiences with exception handling.


Just send me an email at melkior@mediaone.net

- Steve Crocker

Virtual destructor
Implement all of your destructors as virtual if your class serves as a base class and will be
derived from. In other words, if there is a remote chance that other classes ever derive
from it make the destructor virtual. This way proper destruction of derived objects will
occur.

You might also like