Search code examples
c++exceptionexception-specification

Is there a generally accepted idiom for indicating C++ code can throw exceptions?


I have seen problems when using C++ code that, unexpectedly to the caller, throws an exception. It's not always possible or practical to read every line of a module that you are using to see if it throws exceptions and if so, what type of exception.

Are there established idioms or "best practices" that exist for dealing with this problem?

I've thought of the following:

  1. In our doxygen documentation, we could add a comment in every function that is expected to throw an exception and it's type(s).

    • Pluses: Simple.
    • Minuses: Subject to user error.
  2. We could have an app-wide try/catch(...) for safety.

    • Pluses: We won't have any more uncaught exceptions.
    • Minuses: The exception is caught far away from the throw. It's hard to figure out what to do or what went wrong.
  3. Use Exception Specifications

    • Pluses: This is the language-sanctioned way of dealing with this problem.
    • Minuses: Refactoring of problem libraries needed for this to be effective. Not enforced at compile-time, so violations turn into run-time problems, which is what I'm trying to avoid!

Any experiences with these methods, or any additional methods that I'm unaware of?


Solution

  • The idiomatic way to solve the problem is not to indicate that your code can throw exceptions, but to implement exception safety in your objects. The standard defines several exception guarantees objects should implement:

    • No-throw guarantee: The function will never throw an exception
    • Strong exception safety guarantee: If an exception is thrown, the object will be left in its initial state.
    • Basic exception safety guarantee: If an exception is thrown, the object be left in a valid state.

    And of course, the standard documents the level of exception safety for every standard library class.

    That's really the way to deal with exceptions in C++. Rather than marking which code can or can not throw exceptions, use RAII to ensure your objects get cleaned up, and put some thought into implementing the appropriate level of exception safety in your RAII objects, so they're able to survive without special handling if an exception is thrown.

    Exceptions only really cause problems if they allow your objects to be left in an invalid state. That should never happen. Your objects should always implement at least the basic guarantee. (and implementing a container class which provides the proper level of exception safety is an enlightening C++ exercise ;))

    As for documentation, when you're able to determine for certain which exceptions a function may throw, by all means feel free to document it. But in general, when nothing else is specified, it is assumed that a function may throw. The empty throw specfication is sometimes used to document when a function never throws. If it's not there, assume that the function may throw.