Should I inherit from std::exception?
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.
Related videos on Youtube
Konstantin Gizdarski
Full-stack software developer, solution architect, and Agile practitioner. Founder and principal consultant at ClearEye Consulting.
Updated on October 26, 2020Comments
-
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. Withstd::exception
it seems that all you get is awhat()
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 fromstd::exception
?-
sbi over 14 yearsYou might want to have a look at this: stackoverflow.com/questions/1605778/1605852#1605852
-
Christian Rau almost 11 yearsThough 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 over 14 yearsdon'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 over 14 yearsI think the take away is that "throw e;" is evil, and "throw;" is ok.
-
Kirill V. Lyadvinsky over 14 yearsYes,
throw;
is ok, but it is not obvious that you should write something like this. -
Martin York over 14 yearsThere is no way to pass a message to std::exception. std::runtime_error accepts a string and is derived from std::exception.
-
Mark Ransom over 14 yearsNow that was a dumb mistake - certainly I know better. stackoverflow.com/questions/1095225/…
-
James Schek over 14 yearsIt's especially painful for Java developers where rethrow is done using "throw e;"
-
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 over 13 yearsHowever 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 over 13 yearsConsider 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 over 13 yearsDeriving 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 over 13 yearsIt 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 over 13 yearsYou 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 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 over 13 yearsI 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 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 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 over 10 years@Emil: That follows from what I said.
-
Emil over 10 yearsI don't know where you got the idea that exceptions are for logging purposes only. :)
-
Martin York over 10 years@Emil: Not the exception. The text in the exception.
-
Emil over 10 yearsThere 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 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 over 10 yearsThey 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 over 10 yearsBut 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 over 10 yearsThe 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 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 over 10 yearsI 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 thanthrow 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 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 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 over 9 yearsYou'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 over 9 yearsThe 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 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 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 about 8 years
-
Nikolai Fetissov about 8 yearsSo what's your point? Definition implies declaration, what do you see being wrong here?
-
Justin Time - Reinstate Monica almost 8 yearsMSVC adds a constructor to
std::exception
that takes aconst 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 almost 8 yearsYou 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 over 3 yearsstd::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.