By eliminating one of the reasons for if statements.
The commonly used alternative to try / catch / throw is to
return a return code (sometimes called an error code)
that the caller explicitly tests via some conditional statement such
as if. For example,
Although the return code technique is sometimes the most appropriate error handling technique, there are some nasty side effects to adding unnecessary if statements:
So compared to error reporting via return-codes and if, using try / catch / throw is likely to result in code that has fewer bugs, is less expensive to develop, and has faster time-to-market. Of course if your organization doesn't have any experiential knowledge of try / catch / throw, you might want to use it on a toy project first just to make sure you know what you're doing you should always get used to a weapon on the firing range before you bring it to the front lines of a shooting war.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Throw an exception.
Constructors don't have a return type, so it's not possible to use return codes. The best way to signal constructor failure is therefore to throw an exception. If you don't have the option of using exceptions, the "least bad" work-around is to put the object into a "zombie" state by setting an internal status bit so the object acts sort of like it's dead even though it is technically still alive.
The idea of a "zombie" object has a lot of down-side. You need to add a query ("inspector") member function to check this "zombie" bit so users of your class can find out if their object is truly alive, or if it's a zombie (i.e., a "living dead" object), and just about every place you construct one of your objects (including within a larger object or an array of objects) you need to check that status flag via an if statement. You'll also want to add an if to your other member functions: if the object is a zombie, do a no-op or perhaps something more obnoxious.
In practice the "zombie" thing gets pretty ugly. Certainly you should prefer exceptions over zombie objects, but if you do not have the option of using exceptions, zombie objects might be the "least bad" alternative.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Write a message to a log-file. Or call Aunt Tilda. But do not throw an exception!
Here's why (buckle your seat-belts):
The C++ rule is that you must never throw an exception from a destructor that
is being called during the "stack unwinding" process of another exception.
For example, if someone says
During stack unwinding, all the local objects in all those stack frames are
destructed. If one of those destructors throws an exception (say it
throws a Bar object), the C++ runtime system is in a no-win situation:
should it ignore the Bar and end up in the
So the C++ language guarantees that it will call
The easy way to prevent this is never throw an exception from a destructor. But if you really want to be clever, you can say never throw an exception from a destructor while processing another exception. But in this second case, you're in a difficult situation: the destructor itself needs code to handle both throwing an exception and doing "something else", and the caller has no guarantees as to what might happen when the destructor detects an error (it might throw an exception, it might do "something else"). So the whole solution is harder to write. So the easy thing to do is always do "something else". That is, never throw an exception from a destructor.
Of course the word never should be "in quotes" since there is always some situation somewhere where the rule won't hold. But certainly at least 99% of the time this is a good rule of thumb.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Every data member inside your object should clean up its own mess.
If a constructor throws an exception, the object's destructor is not run. If your object has already done something that needs to be undone (such as allocating some memory, opening a file, or locking a semaphore), this "stuff that needs to be undone" must be remembered by a data member inside the object.
For example, rather than allocating memory into a raw
By the way, if you think your Fred class is going to be allocated into a smart pointer, be nice to your users and create a typedef within your Fred class:
That typedef simplifies the syntax of all the code that uses your objects:
your users can say
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
If what you really want to do is work with strings, don't use an array of char in the first place, since arrays are evil. Instead use an object of some string-like class.
For example, suppose you want to get a copy of a string, fiddle with the copy, then append another string to the end of the fiddled copy. The array-of-char approach would look something like this:
Using
The
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised May 2, 2003