For convenience, HasPointers uses the MyData class as a handle to the two pointers. Whenever it’s time to allocate more memory, whether during construction or assignment, the first clone function is ultimately called to do the job. If memory fails for the first call to the new operator, a bad_alloc exception is thrown automatically. If it happens on the second allocation (for theInts), we have to clean up the memory for theString—hence the first try block that catches a bad_alloc exception. The second try block isn’t crucial here because we’re just copying ints and pointers (so no exceptions will occur), but whenever you copy objects, their assignment operators can possibly cause an exception, in which case everything needs to be cleaned up. In both exception handlers, notice that we
If you inspect the previous code closely, you’ll notice that none of the delete operations will throw an exception. This code actually depends on that fact. Recall that when you call delete on an object, the object’s destructor is called. It turns out to be practically impossible, therefore, to design exception-safe code without assuming that destructors don’t throw exceptions. Don’t let destructors throw exceptions! (We’re going to remind you about this once more before this chapter is done)[7] .
Programming with exceptions
For most programmers, especially C programmers, exceptions are not available in their existing language and take a bit of adjustment. Here are some guidelines for programming with exceptions.
When to avoid exceptions
Exceptions aren’t the answer to all problems. In fact, if you simply go looking for something to pound with your new hammer, you’ll cause trouble. The following sections point out situations in which exceptions are
Not for asynchronous events
The Standard C signal( ) system and any similar system handle asynchronous events: events that happen outside the flow of a program, and thus events the program cannot anticipate. You cannot use C++ exceptions to handle asynchronous events because the exception and its handler are on the same call stack. That is, exceptions rely on the dynamic chain of function calls on the program’s runtime stack (dynamic scope, if you will), whereas asynchronous events must be handled by completely separate code that is not part of the normal program flow (typically, interrupt service routines or event loops). Don’t throw exceptions from interrupt handlers.
This is not to say that asynchronous events cannot be
Not for benign error conditions
If you have enough information to handle an error, it’s not an exception. Take care of it in the current context rather than throwing an exception to a larger context.
Also, C++ exceptions are not thrown for machine-level events such as divide-by-zero.[8] It’s assumed that some other mechanism, such as the operating system or hardware, deals with these events. In this way, C++ exceptions can be reasonably efficient, and their use is isolated to program-level exceptional conditions.
Not for flow-of-control
An exception looks somewhat like an alternate return mechanism and somewhat like a switch statement, so you might be tempted to use an exception instead of these ordinary language mechanisms. This is a bad idea, partly because the exception-handling system is significantly less efficient than normal program execution; exceptions are a rare event, so the normal program shouldn’t pay for them. Also, exceptions from anything other than error conditions are quite confusing to the user of your class or function.
You’re not forced to use exceptions