[ACCEPTED]-Should I inherit from std::exception?-exception-handling
The main benefit is that code using your 5 classes doesn't have to know exact type 4 of what you throw
at it, but can just catch
the std::exception
.
Edit: as 3 Martin and others noted, you actually want 2 to derive from one of the sub-classes of 1 std::exception
declared in <stdexcept>
header.
The problem with std::exception
is that there is no constructor 6 (in the standard compliant versions) that 5 accepts a message.
As a result I prefer to 4 derive from std::runtime_error
. This is derived from std::exception
but 3 its constructors allow you to pass a C-String 2 or a std::string
to the constructor that will be returned 1 (as a char const*
) when what()
is called.
Reason for inheriting from std::exception
is it "standard" base 5 class for exceptions, so it is natural for 4 other people on a team, for example, to 3 expect that and catch base std::exception
.
If you are looking 2 for convenience, you can inherit from std::runtime_error
that 1 provides std::string
constructor.
I once participated in the clean up of a 12 large codebase where the previous authors 11 had thrown ints, HRESULTS, std::string, char*, random 10 classes... different stuff everywhere; just 9 name a type and it was probably thrown somewhere. And 8 no common base class at all. Believe me, things 7 were much tidier once we got to the point 6 that all the thrown types had a common base 5 we could catch and know nothing was going 4 to get past. So please do yourself (and 3 those who'll have to maintain your code 2 in future) a favor and do it that way from 1 the start.
You should inherit from boost::exception. It provides a 3 lot more features and well-understood ways 2 to carry additional data... of course, if 1 you're not using Boost, then ignore this suggestion.
Yes you should derive from std::exception
.
Others have 8 answered that std::exception
has the problem that you 7 can't pass a text message to it, however 6 it is generally not a good idea to attempt 5 to format a user message at the point of 4 the throw. Instead, use the exception object 3 to transport all relevant information to 2 the catch site which can then format a user-friendly 1 message.
The reason why you might want to inherit 3 from std::exception
is because it allows you to throw 2 an exception that is caught according to 1 that class, ie:
class myException : public std::exception { ... };
try {
...
throw myException();
}
catch (std::exception &theException) {
...
}
There is one problem with inheritance that 10 you should know about is object slicing. When 9 you write throw e;
a throw-expression initializes 8 a temporary object, called the exception 7 object, the type of which is determined 6 by removing any top-level cv-qualifiers 5 from the static type of the operand of throw
. That 4 could be not what you're expecting. Example 3 of problem you could find here.
It is not an 2 argument against inheritance, it is just 1 'must know' info.
Difference: std::runtime_error vs std::exception()
Whether you should inherit from it or not is up 7 to you. Standard std::exception
and its standard descendants 6 propose one possible exception hierarchy 5 structure (division into logic_error
subhierarchy and 4 runtime_error
subhierarchy) and one possible exception 3 object interface. If you like it - use it. If 2 for some reason you need something different 1 - define your own exception framework.
Whether to derive from any standard exception 28 type or not is the first question. Doing 27 so enables a single exception handler for 26 all standard library exceptions and your 25 own, but it also encourages such catch-them-all 24 handlers. The problem is that one should 23 only catch exceptions one knows how to handle. In 22 main(), for example, catching all std::exceptions 21 is likely a good thing if the what() string 20 will be logged as a last resort before exiting. Elsewhere, however, it's 19 unlikely to be a good idea.
Once you've decided 18 whether to derive from a standard exception 17 type or not, then the question is which 16 should be the base. If your application 15 doesn't need i18n, you might think that 14 formatting a message at the call site is 13 every bit as good as saving information 12 and generating the message at the call site. The 11 problem is that the formatted message may 10 not be needed. Better to use a lazy message 9 generation scheme -- perhaps with preallocated 8 memory. Then, if the message is needed, it 7 will be generated on access (and, possibly, cached 6 in the exception object). Thus, if the 5 message is generated when thrown, then a 4 std::exception derivate, like std::runtime_error 3 is needed as the base class. If the message 2 is generated lazily, then std::exception 1 is the appropriate base.
If all your possible exceptions derive from 7 std::exception
, your catch block can simply catch(std::exception & e)
and be assured 6 of capturing everything.
Once you've captured 5 the exception, you can use that what
method 4 to get more information. C++ doesn't support 3 duck-typing, so another class with a what
method 2 would require a different catch and different 1 code to use it.
Since the language already throws std::exception, you 7 need to catch it anyway to provide decent 6 error reporting. You may as well use that 5 same catch for all unexpected exceptions 4 of your own. Also, almost any library that 3 throws exceptions would derive them from 2 std::exception.
In other words, its either 1
catch (...) {cout << "Unknown exception"; }
or
catch (const std::exception &e) { cout << "unexpected exception " << e.what();}
And the second option is definitely better.
Another reason to sub-class exceptions is 17 a better design aspect when working on large 16 encapsulated systems. You can reuse it for 15 things such as validation messages, user 14 queries, fatal controller errors and so 13 on. Rather than rewriting or rehooking all 12 of your validation like messages you can 11 simply "catch" it on the main source file, but 10 throw the error anywhere in your entire 9 set of classes.
e.g. A fatal exception will 8 terminate the program, a validation error 7 will only clear the stack and a user query 6 will ask the end-user a question.
Doing it 5 this way also means you can reuse the same 4 classes but on different interfaces. e.g. A 3 windows application can use message box, a 2 web service will show html and reporting 1 system will log it and so on.
Though this question is rather old and has 17 already been answered plenty, I just want 16 to add a note on how to do proper exception 15 handling in C++11, since I am continually 14 missing this in discussions about exceptions:
Use std::nested_exception
and std::throw_with_nested
It 13 is described on StackOverflow here and here, how 12 you can get a backtrace on your exceptions inside your code without need for 11 a debugger or cumbersome logging, by simply 10 writing a proper exception handler which 9 will rethrow nested exceptions.
Since you 8 can do this with any derived exception class, you 7 can add a lot of information to such a backtrace! You 6 may also take a look at my MWE on GitHub, where a backtrace 5 would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
You don't even need to subclass std::runtime_error
in order to get plenty of information when an exception is thrown.
The only 4 benefit I see in subclassing (instead of 3 just using std::runtime_error
) is that your exception handler 2 can catch your custom exception and do something 1 special. For example:
try
{
// something that may throw
}
catch( const MyException & ex )
{
// do something specialized with the
// additional info inside MyException
}
catch( const std::exception & ex )
{
std::cerr << ex.what() << std::endl;
}
catch( ... )
{
std::cerr << "unknown exception!" << std::endl;
}
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.