Should I inherit from std::exception?

35,542

Solution 1

The main benefit is that code using your classes doesn't have to know exact type of what you throw at it, but can just catch the std::exception.

Edit: as Martin and others noted, you actually want to derive from one of the sub-classes of std::exception declared in <stdexcept> header.

Solution 2

The problem with std::exception is that there is no constructor (in the standard compliant versions) that accepts a message.

As a result I prefer to derive from std::runtime_error. This is derived from std::exception but its constructors allow you to pass a C-String or a std::string to the constructor that will be returned (as a char const*) when what() is called.

Solution 3

Reason for inheriting from std::exception is it "standard" base class for exceptions, so it is natural for other people on a team, for example, to expect that and catch base std::exception.

If you are looking for convenience, you can inherit from std::runtime_error that provides std::string constructor.

Solution 4

I once participated in the clean up of a large codebase where the previous authors had thrown ints, HRESULTS, std::string, char*, random classes... different stuff everywhere; just name a type and it was probably thrown somewhere. And no common base class at all. Believe me, things were much tidier once we got to the point that all the thrown types had a common base we could catch and know nothing was going to get past. So please do yourself (and those who'll have to maintain your code in future) a favor and do it that way from the start.

Solution 5

You should inherit from boost::exception. It provides a lot more features and well-understood ways to carry additional data... of course, if you're not using Boost, then ignore this suggestion.

Share:
35,542

Related videos on Youtube

Konstantin Gizdarski
Author by

Konstantin Gizdarski

Full-stack software developer, solution architect, and Agile practitioner. Founder and principal consultant at ClearEye Consulting.

Updated on October 26, 2020

Comments

  • Konstantin Gizdarski
    Konstantin Gizdarski over 3 years

    I've seen at least one reliable source (a C++ class I took) recommend that application-specific exception classes in C++ should inherit from std::exception. I'm not clear on the benefits of this approach.

    In C# the reasons for inheriting from ApplicationException are clear: you get a handful of useful methods, properties and constructors and just have to add or override what you need. With std::exception it seems that all you get is a what() method to override, which you could just as well create yourself.

    So what are the benefits, if any, of using std::exception as a base class for my application-specific exception class? Are there any good reasons not to inherit from std::exception?

    • sbi
      sbi over 14 years
      You might want to have a look at this: stackoverflow.com/questions/1605778/1605852#1605852
    • Christian Rau
      Christian Rau almost 11 years
      Though as a side note unrelated to the particular question, C++ classes you take need not neccessarily be reliable sources on good practices just out of their own right.
  • jmucchiello
    jmucchiello over 14 years
    don't subclass std::exception and then catch (std::exception e). You need to catch a reference to std::exception& (or a pointer) or else you are slicing off the subclass data.
  • James Schek
    James Schek over 14 years
    I think the take away is that "throw e;" is evil, and "throw;" is ok.
  • Kirill V. Lyadvinsky
    Kirill V. Lyadvinsky over 14 years
    Yes, throw; is ok, but it is not obvious that you should write something like this.
  • Martin York
    Martin York over 14 years
    There is no way to pass a message to std::exception. std::runtime_error accepts a string and is derived from std::exception.
  • Mark Ransom
    Mark Ransom over 14 years
    Now that was a dumb mistake - certainly I know better. stackoverflow.com/questions/1095225/…
  • James Schek
    James Schek over 14 years
    It's especially painful for Java developers where rethrow is done using "throw e;"
  • Konstantin Gizdarski
    Konstantin Gizdarski about 14 years
    +1, good point. Both from a separation of concerns and an i18n perspective, it's definitely better to let the presentation layer construct the user message.
  • Emil
    Emil over 13 years
    However note that boost::exception itself does not derive from std::exception. Even when deriving from boost::exception, you should also derive from std::exception (as a separate note, whenever deriving from exception types, you should use virtual inheritance.)
  • Emil
    Emil over 13 years
    Consider only deriving from abstract base types. Catching an abstract base type by value will give you an error (avoiding slicing); catching an abstract base type by reference then trying to throw a copy of it will give you an error (again avoiding slicing.)
  • Emil
    Emil over 13 years
    Deriving from any other standard exception type except for std::exception is probably not a good idea. The problem is that they derive from std::exception non-virtually, which can lead to subtle bugs involving multiple inheritance where a catch(std::exception&) might silently fail to catch an exception due to the conversion to std::exception being ambiguous.
  • Emil
    Emil over 13 years
    It is not a good idea to format a user-friendly message at the point of the throw because this would couple lower-level code with with localization functionality and whatnot. Instead, store in the exception object all relevant information, and let the catch site format a user-friendly message based on the exception type and the data it carries.
  • Emil
    Emil over 13 years
    You shouldn't be passing a message to the exception type constructor (consider that messages need to be localized.) Instead, define an exception type that categorizes the error semantically, store in the exception object what you need to format a user-friendly message, then do so at the catch site.
  • Martin York
    Martin York over 13 years
    @ Emil: Sure if you're exception carry user displayable messages, though generally they are for logging purposes only. At the throw site you don't have the context to build a user message (as this may be a library anyway). The catch site will have more context and can generate the appropriate msg.
  • Martin York
    Martin York over 13 years
    I read the article on boost on the subject. It seems reasonable in a pure logic sense. But I have never seen MH in exceptions in the wild. Nor would I consider using MH in exceptions so it seems like a sledgehammer to fix a non existent problem. If this was a real problem I am sure we would have seen action on it from the standards committee to fix such an obvious flaw. So my opinion is that std::runtime_error (and family) are still perfectly acceptable exception to throw or derive from.
  • Mooing Duck
    Mooing Duck over 10 years
    @Emil: Deriving from other standard exceptions besides std::exception is an excellent idea. What you shouldn't do is inherit from more than one.
  • Emil
    Emil over 10 years
    @MooingDuck: If you derive from more than one standard exception type you'll end up with std::exception being derived (non-virtually) multiple times. See boost.org/doc/libs/release/libs/exception/doc/….
  • Mooing Duck
    Mooing Duck over 10 years
    @Emil: That follows from what I said.
  • Emil
    Emil over 10 years
    I don't know where you got the idea that exceptions are for logging purposes only. :)
  • Martin York
    Martin York over 10 years
    @Emil: Not the exception. The text in the exception.
  • Emil
    Emil over 10 years
    There should be no text in the exception, only data that is needed to handle it. In the case when handling the exception involves notifying the user about the problem, the data in the exception needs to be sufficient to format a friendly message at the point of the catch. It is incorrect to format the message at the point of the throw because 1) there may not be enough information to do that, and 2) it might have to be translated to different languages.
  • Martin York
    Martin York over 10 years
    @Emil: We have already gone through this argument. Where I pointed out that that is not what you are putting in the exception. You understanding of the subject seems good but your argument is flawed. Error messages generated for the user are completely different from log messages for the developer.
  • Martin York
    Martin York over 10 years
    They have nothing to do with each other. At the catch point you can make nice message but the information in the exception is usually not relevant because it is too technical (maybe a file name is useful or something very general like that). So error messages for the user are generated at the catch point and usually use very little from the exception as that information is too technical.
  • Martin York
    Martin York over 10 years
    But at the catch point any data is to technical to make an error message for the log with out generalization which would practically make it usless. So log messages need to be generated at the point of the exception so that we do not loose information. Of course there are exceptions and generalizations but its a good rule of thumb.
  • Emil
    Emil over 10 years
    The data that may be needed to format a friendly message are innumerable, but here are some examples: file name, user name, any other name, port number, ip address, url, required image dimensions, required image format, error code (to be converted to string at the catch site), time/date stamps, ...
  • Martin York
    Martin York over 10 years
    @Emil: I already mentioned that. Does not change my point about logging. Log messages must be generated at the throw point to prevent loss of information. Thus your statement <quote>There should be no text in the exception</quote> is just wrong.
  • Emil
    Emil over 10 years
    I didn't mean text as in "string", but as in "message". The point I'm making is that many programmers are tempted to write throw error("File not found") (which is wrong) rather than throw file_not_found_error() (which is correct). And let's not confuse people with logging. Yes, you can log the fact that you throw or catch an exception, and yes some data the exception may transport is not for the user to see, but that's besides the point.
  • Martin York
    Martin York over 10 years
    @Emil: I agree that you can't do formatting of error messages at the throw point. But again you are going off on another completely different side track (and again having nothing to do with the question). I can NOT agree with that statement in the last comment. All (the ones I have used) I18N packages use strings as the index to pull the actual message from a resource so either of those is fine. Bad really you need to start your own question and get more opinions.
  • alfC
    alfC almost 10 years
    @JohnMGant and Emil: Interesting, can you point to a concrete example on how this can be done. I understand that one can derive from std::exception and carry the information of the exception. But who will be responsible for building/format the error message? The ::what() function or something else?
  • Emil
    Emil over 9 years
    You'd format the message at the catch site, most likely at the application (rather than library) level. You catch it by type, then probe it for information, then localize/format the appropriate user message.
  • Emil
    Emil over 9 years
    The implementation allows you to efficiently catch exceptions by their type, that's why you should use different types to indicate different failures, rather than using the same type (string) but different values. E.g. you can catch(file_open_error&) and let everything else pass through.
  • Martin York
    Martin York over 9 years
    @Emil. This discussion is a year old. Create your own question at this point. Your arguments as far as I am concerned are just wrong (and based on votes people tend to agree with me). See What is a 'good number' of exceptions to implement for my library? and Is catching general exceptions really a bad thing? You have not provided any nw information since your previous diatribe.
  • mip
    mip over 8 years
    @Emil I would say throw file_not_found_error("File not found") is correct, because if code will catch it as generic exception you want to leave user with some human friendly popup.
  • Alexander Shukaev
    Alexander Shukaev about 8 years
    std::exception is defined in the <exception> header (proof). -1
  • Nikolai Fetissov
    Nikolai Fetissov about 8 years
    So what's your point? Definition implies declaration, what do you see being wrong here?
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica almost 8 years
    MSVC adds a constructor to std::exception that takes a const char* const, presumably to ease with implementing the classes in <stdexcept> by offloading shared code to the shared base class, but relying on that breaks portability. Figured that might be relevant, if not very useful.
  • Justin Time - Reinstate Monica
    Justin Time - Reinstate Monica almost 8 years
    You can also solve this problem by adding a member function, raise(), as such: virtual void raise() { throw *this; }. Just remember to override it in each derived exception.
  • plexando
    plexando over 3 years
    std::exception has a virtual what(). Even if you only derive from std::exception, your exception type is expected to put something into (i.e., override) that what() to be generally useful. Why not simply derive from something like std::runtime_error? Then you have both a custom what() for somebody just catching std::exception and dedicated, structured error data to inspect if someone really wants to catch your particular error class. Best of both worlds.