20.8 — Exception dangers and downsides

As with almost everything that has benefits, there are some potential downsides to exceptions as well. This article is not meant to be comprehensive, but just to point out some of the major issues that should be considered when using exceptions (or deciding whether to use them).

Cleaning up resources

One of the biggest problems that new programmers run into when using exceptions is the issue of cleaning up resources when an exception occurs. Consider the following example:

What happens if WriteFile() fails and throws a FileException? At this point, we’ve already opened the file, and now control flow jumps to the FileException handler, which prints an error and exits. Note that the file was never closed! This example should be rewritten as follows:

This kind of error often crops up in another form when dealing with dynamically allocated memory:

If processPerson() throws an exception, control flow jumps to the catch handler. As a result, john is never deallocated! This example is a little more tricky than the previous one -- because john is local to the try block, it goes out of scope when the try block exits. That means the exception handler can not access john at all (its been destroyed already), so there’s no way for it to deallocate the memory.

However, there are two relatively easy ways to fix this. First, declare john outside of the try block so it does not go out of scope when the try block exits:

Because john is declared outside the try block, it is accessible both within the try block and the catch handlers. This means the catch handler can do cleanup properly.

The second way is to use a local variable of a class that knows how to cleanup itself when it goes out of scope (often called a “smart pointer”). The standard library provides a class called std::unique_ptr that can be used for this purpose. std::unique_ptr is a template class that holds a pointer, and deallocates it when it goes out of scope.

We’ll talk more about smart pointers in the next chapter.

Exceptions and destructors

Unlike constructors, where throwing exceptions can be a useful way to indicate that object creation did not succeed, exceptions should never be thrown in destructors.

The problem occurs when an exception is thrown from a destructor during the stack unwinding process. If that happens, the compiler is put in a situation where it doesn’t know whether to continue the stack unwinding process or handle the new exception. The end result is that your program will be terminated immediately.

Consequently, the best course of action is just to abstain from using exceptions in destructors altogether. Write a message to a log file instead.

Performance concerns

Exceptions do come with a small performance price to pay. They increase the size of your executable, and they may also cause it to run slower due to the additional checking that has to be performed. However, the main performance penalty for exceptions happens when an exception is actually thrown. In this case, the stack must be unwound and an appropriate exception handler found, which is a relatively expensive operation.

As a note, some modern computer architectures support an exception model called zero-cost exceptions. Zero-cost exceptions, if supported, have no additional runtime cost in the non-error case (which is the case we most care about performance). However, they incur an even larger penalty in the case where an exception is found.

So when should I use exceptions?

Exception handling is best used when all of the following are true:

  • The error being handled is likely to occur only infrequently.
  • The error is serious and execution could not continue otherwise.
  • The error cannot be handled at the place where it occurs.
  • There isn’t a good alternative way to return an error code back to the caller.

As an example, let’s consider the case where you’ve written a function that expects the user to pass in the name of a file on disk. Your function will open this file, read some data, close the file, and pass back some result to the caller. Now, let’s say the user passes in the name of a file that doesn’t exist, or a null string. Is this a good candidate for an exception?

In this case, the first two bullets above are trivially met -- this isn’t something that’s going to happen often, and your function can’t calculate a result when it doesn’t have any data to work with. The function can’t handle the error either -- it’s not the job of the function to re-prompt the user for a new filename, and that might not even be appropriate, depending on how your program is designed. The fourth bullet is the key -- is there a good alternative way to return an error code back to the caller? It depends on the details of your program. If so (e.g. you can return a null pointer, or a status code to indicate failure), that’s probably the better choice. If not, then an exception would be reasonable.

20.9 -- Exception specifications and noexcept
20.7 -- Function try blocks

33 comments to 20.8 — Exception dangers and downsides

  • Remy

    Hi Alex and Nascar~

    Why is it that we can copy initialize and uniform initialize again for the variable john in this code?

  • zakaria

    Hello guys!
    I wanted to point out a small error:
    The parenthesis in (often called a “smart pointer”... is never closed.
    Thanks for this amazing website as always!

  • hellmet

    A small naggy suggestion :)

    "As a result, john is never deallocated!" would be better phrased as "As a result, john object on heap is never deallocated! [...]  because pointer to john is local to the try block, it goes out of scope when the try block exits."

  • Hi Alex!

    Example 5 has a semicolon in line 1.
    This lesson doesn't use brace initialization and is using `NULL` for pointers.

  • Sean Kelly

    Hello Alex!

    Just a question for clarification when you said:
    "exception handling is best used for truly exceptional cases and catastrophic errors, not for routine error handling."

    Are you talking about things that cause the program to crash specifically? Like trying to access memory
    that is out of range in an array? Where do you draw the line when it comes to using expectations rather than
    checks to fix problems?


  • Curiosity

    In the above segment, Why does "DESTRUCTING A" gets printed? And Why does "EXCEPTION CAUGHT" gets printed after "DESTRUCTING A"?
    (I know why "terminate called after throwing an instance of 'char const*'" gets  printed, so no need to bother about that.)
    Help Please ! Thanks in Advance :)

    • Curiosity

      There is some editing error on Line No. 15.
      It should be like :-

    • Alex

      Inherited classes get built from most parent to most child, so when you create a C, the constructor order is A, then B, then C. So A gets constructed first, which goes fine. Then B throws an exception. Because A has already been fully constructed, the compiler will call the destructor for A before the exception is caught. This gives A a chance to clean up before the exception is handled.

      • Curiosity

        But, The Object hasn't even got Out of scope. So, Why does it call the Destructor of A? Is there any Valid reason behind It?
        Thanks In Advance :)

        • Alex

          > This gives A a chance to clean up before the exception is handled.

          • Curiosity

            My question was : Why is this chance given?
            There is no need because it will be automatically destroyed after getting out of scope.

            • Alex

              C++ does not allow partially constructed objects. This means that if one of the constructors fails, the object is considered dead. Any created sub-parts (inherited classes or instantiated members) are destroyed as part of this process.

              • Curiosity

                Here, A is the base class, So As It is a part of the Inheritance chain, It gets Destroyed. But what if A is not connected to B in any terms, It doesnt get affected, No?( It is obvious, but still !)
                Thanks :)


    why there is no comprehensive quiz for this and later chapters?
    and when is chapter 15 coming?
    and thanks for your great tutorials.

    • Alex

      There is a comprehensive quiz for this chapter -- I just fixed the link from this lesson to it. I'll add comprehensive quizzes to future chapters as I update them.

      Also the first lesson of chapter 15 is up. I'll continue to write lessons as time permits.

  • Charlie

    You should add that most 64bit systems now have the "zero-cost exceptions". Basically, as I have understood, they store a table at a cold-code spot, so when no exception is thrown, it is as fast as no exception checking. Although when the program throws one, it is quite slower than normal 32bit exceptions. It also makes your executable file quite bigger!

  • Darren

    What when we've dynamically allocated memory **within** a function say that then throws an exception before deleting the allocation, and the try-catch block is in the calling environment? For example:

    The pointer is not in the scope of the catch block so we cannot delete it's contents. For this simple example this is not an issue as main terminates after the exception is caught however for a larger program it would be a memory leak if the program continues to run.

    Just thought of the solution. Typically we're using a conditional to check the state of some variable or other and if that conditional evaluates to true we thrown an exception. If we've allocated memory at the start of the function then the function needs to clean that up before the exception is thrown:

    Or just use smart pointers like std::unique_ptr that will do this for me.

  • Kiran C K

    Under Exceptions and destructors , in the line below:

    "The problem occurs when an exception is thrown from a destructor during the stack unwinding process. If that happens, the compiler is put in a situation where it doesn’t know whether to continue the stack unwinding process or handle the new exception"

    Isn't handling the exception the end of the stack unwinding process? It handles the exception after unwinding the stack, right? I did not get the line that the compiler will put in a situation where it doesn’t know whether to continue the stack unwinding process or handle the new exception.

    Let me put it this way, why does both happen at the same time, when exceptions are thrown in destructors?

    • Alex

      When an exception is thrown, the stack is unwound until a handler is found (or until everything has been popped off the stack).

      Assume an exception has been thrown, and in the process of unwinding the stack, a new exception is thrown. At this point, the compiler could reasonably say, "I still haven't found a handler for my original exception, so I'm going to ignore this one and continue looking for a handler". This isn't great because the new exception will never get handled. Alternatively, the compiler could reasonably say, "This new exception is newer, so I'm going to look for a handler for it instead". This isn't great because the original exception will never get handled.

      Because of this, throwing an exception while another exception is being handled will cause the program to abort.

  • Awais Ali

    I just simply loved the tutorial. They are far better than any book and the examples are very good to help one clear his doubts. And I would love to see something on Design Patterns. :)

  • Ashwini

    Thanks Alex!!! I have read your tutorial from start to finish and it has been of immense help to me. I am much more confident in C++ programming now. Hope to see more tutorials from you :-)

  • Adel

    By far, this is the best and simplest tutorial I have come across. Thanks a lot Alex, it was a pleasure to read. One of the nicest things about it (other than being well written and simple) is that it explains the need behind the various language features before explaining how they work/should be used.

  • bryce

    Thanks Alex!!! I've read your tuts from start to finish, and i've learned a huge amout on C++ programming! now i'm going to move onto some books, i think what i've learned here will become the foundation of my C++ knowledge for me to build on!

    Only thing i could think of is add more exercises....i really missed them in the later chapters.

    Thanks again,

  • Kiena

    Alternatively the 4th example could be written as:

    Like this the cleanup code appears only once.

    This is similar to the "finally" manner in other languages, except in c++ it still won't be executed when a non-handled kind of exception occurs, which applies to the original code too.

    • Alex

      This is only a good solution if catch actually handles the exception. If the catch block rethrows the exception then the delete statement below the catch block would never execute.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]