17 Comments

  1. The C++ Cleaner

    > Conclusion

    The fourth case would be adding information for the user. But noone thinks about proper error messages.

    Reply
    1. Arne Mertz

      Adding information can be a valid reason for catching an exception. However, in most cases where I have seen information added to an exception it was not helpful for the user but should have been written to a log file for a maintainer instead.

      Usually if an action fails due to an exception you can only catch it at the appropiate level and give the user a message “there has been an error performing that action (and you can do nothing about it)”.

      Exceptions caught early and rethrown with added information more often than not turn out to lead to messages like “there has been an error performing that action because something went wrong in function foo, file X, line Y (and you still can’t do anything about it)”

      In many, but not all cases, when you can do something about it, e.g. provide correct input, that should be checked before the throwing function is called. A usual exception that can not be checked beforehand is a network error or database connection loss. Those would be the rare cases where you could indeed add some information to let the user check the network etc.

      Reply
      1. The C++ Cleaner

        > Those would be the rare cases

        I differ errors according to recoverability and include a Retry button in the error dialog. Many many many errors are recoverable (including removing floppy disc while writing; tests with Windows NT 4).
        Exceptions are a superb mechanism to transport and extend all info needed by user or support. “But noone thinks about proper error messages.” == no transport is needed == cheapest try throw catch used == no benefit for user and support == ultimately replaceable by std::abort(). But if you do it right, the user can skip the usually necessary search for the source of the error.

        Reply

  2. Dadams

    I’m wonderig if it’s a good idea to derive a RAII class from, e.g., boost::noncopyable.

    Reards

    Reply
    1. Arne Mertz

      Depends. There are RAII classes that handle copying (think of `std::shared_ptr`) or are move-only (`std::unique_ptr`). However, many are used only for single, temporary use (typically prefixed `scoped`) and neither copyable nor movable. I’d prefer to explicitly `delete` unsupported operations, since afaik there is no `boost::noncopyable_nonmovable` 😉

      Reply
  3. Martin Ba

    Another point you mention I find interesting is:

    “(…) use a lot of standard library features that can throw exceptions but don’t want to derive your own exception classes from std::exception.”

    I would question the design. Why (serious question) would anyone not derive from std::exception? It doesn’t make any sense to me.

    All examples I know that do not derive from std::exception are historical accidents.

    Are there any real live C++ code bases where *not* deriving std::exception has been a Good Thing?

    cheers,
    Martin

    Reply
    1. Arne Mertz

      While I agree that such a design would be questionable most times, there could be cornecases. Consider writing a sublibrary that for a bigger library you can’t change, whose main exception does not derive from `std::exception`, you then might want to derive `MySubLibBaseException` from that main exception instead of `std::exception`. I would prefer having `std::exception` as single base class, too, although my coding style would explicitly mention a single user defined base exception for all user defined exceptions to facilitate the distinction in catch handlers.

      Reply
      1. Martin Ba

        Distinction *in the catch handler* is mostly a fallacy too, IMHO.

        We must distinguish (write multiple catch clauses) today, because we have different (base) exception classes.

        We then do the same thing (log + rollback) in each handler.

        There might be some cases where we consider the caught “error” to be something else than log+rollback. (Abstractly speaking.) It is highly unlikely that what we consider “something else” is divided along the exception class hierarchy, so we end up with if-s and switches in addition to the multiple catch clauses.

        Reply
        1. Arne Mertz

          I could imagine a distinction in the catch handler if my exception base class provides more info than just what(), e.g. for different levels of detail in the message box and log file.

          Reply

      2. In the embedded world, deriving from std::exception may a ‘no no’ as this pulls in std::string, which uses dynamic allocation for its storage. This may be ‘banned’ as many embedded projects will avoid dynamic memory allocations completely. My own STL-like embedded library defines its own exception base class for this very reason.

        Reply
        1. Arne Mertz

          I am somewhat surprised to hear that you have exceptions at all in the embedded library. I can’t remember any embedded developer I have talked to not mentioning that besides dynamic memory allocations, exceptions are the second forbidden feature in embedded C++.
          Of course, if you don’t use the parts of the standard library that throw `std::exception`, there is no need to derive your own classes from it.

          Reply
  4. Martin Ba

    One of these days I should write my own article about what I think is wrong with exception as implemented today in so many ways.

    Anyways, I’d like to call out one issue here:

    You seem to be opposed to “adding debugging information” (I’d call it context) to the exceptions, as you seem to think that a proper catch site should handle the exception programatically(?), and that “adding information (…) used for debugging (…) should be avoided in production code”.

    To which I can only say: WTF? (In a friendly way :-))

    I think mostly the only sane thing catch-code can do, when you otherwise use proper RAII techniques as you so aptly describe, when a proper, high level catch site catches a base class (and really it should only be catching base classes, right?) is log the full exception information and abort whatever it had been trying.

    The crucial bit here is *log* the *full* information: The more information the better. It might be buried in a log file, it might be totally incomprehensible to the average user, but eventually someone will look at the logs and that someone will be well served by every bit of so called “debugging info” you can offer.

    That’s the reason Java and C# exception with their built-in call stacks are *so* much more useful that what we have in C++, even though they have the same problems otherwise. (Note: I do not propose call stacks for C++ exceptions.)

    That’s the reason I *cringe* when I see the what() message VS offers for std::out_of_range: It’s “Index out of range.” – WTF? How about “Index 7 out of range (0 – 6) in vector object located at address 0x12345678.” – would *that* be too hard to implement? Sure it’s debugging info – and *sure* I want (some) debugging info in my production code!

    cheers,
    Martin

    Reply
    1. Arne Mertz

      Hi Martin, thanks for your thoughts.

      I want to stress that I am not against adding context in general, but against adding information that is only used for debugging, i.e. that can not be seen during normal execution.

      Adding information needed for the correct handling of the error is ok. If handling the error means logging a stack trace (or parts of it) so that support can guess what might be the source of the problem, then adding information about the stack trace is perfectly ok, because that stack trace is needed a the handler site.

      On the other hand, if handling the exception means to ignore it or to just pop up an “Unkown error” message, without logging the what() somewhere, then adding information to that message is useless, unless you are in a debugging session.

      What I have seen in code is that exception modifiers that have been introduced “temporarily” to debug some error remain years after the error is not even possible any more.

      Reply
      1. Martin Ba

        Thanks for the clarifying thoughts.

        Aside: “Unknown Error” messages should be a punishable offense 🙂

        “Anwendung konnte nicht gestartet werden, weil die Anwendungskonfiguration nicht korrekt ist.” – anyone?

        “Unknown error” messages (like the one above) are like telling you: “Oh I known some what went wrong, but I won’t tell you anything.” 🙂

        Reply

  5. Arne, thanks for this post. Both newbies and experienced users will benefit from it.

    You’re point about handling versus translating errors is very good.

    I think there is a role for exceptions in trouble shooting, but not a big one. For that I recommend Boost.Exception which is a safe and sane way to add information to a thrown exception.

    Reply
    1. Arne Mertz

      Hi Jon, thanks for taking the time to read this. Glad you appreciate it.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *