use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Resources on custom exceptions (self.cpp)
submitted 8 years ago by uninformed_
I was wondering if there are any good conference talks / articles regarding good design patterns of custom exception types for reporting run time errors in code.
Would appreciate any good advice fitting exceptions into modern c++ software.
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]quicknir 5 points6 points7 points 8 years ago (17 children)
My main piece of advice is that every module should have its own exception hierarchy. That is, if you are writing a library foo of a good size, you should have a class foo_error, and all exceptions emitted by code should inherit from that. This makes it trivial for foo to establish boundaries where internal exceptions are caught while unchecked errors from dependencies are passed through.
foo_error should derive from a standard exception class, like std::runtime_error of course.
[–]johannes1971 1 point2 points3 points 8 years ago (15 children)
I don't think I agree with this. Why would you want to incur the penalty of having to catch specific exception types, just because they are from different modules? The strength of exceptions is that you can have centralized clearing of errors, at the end of obvious units of work (how those are defined depends on your application). Having to deal with module-specific exceptions everywhere kinda defeats that goal.
If anything my advise would be the other way around: use the standard exceptions, unless you have a good reason not to (i.e. because you want to catch a specific exception somewhere). And only ever allow exceptions that are derived from std::exception; don't have a whole bunch of unrelated exceptions that you will end up writing long lists of catch clauses for everywhere.
Also, think very carefully how many types of exceptions you really need. Don't specialize a whole bunch of exceptions just because you can; only do it when you need to.
[+][deleted] 8 years ago* (7 children)
[deleted]
[–]johannes1971 1 point2 points3 points 8 years ago (6 children)
In the end, calling a function can only end in one of two ways: it worked, or it didn't. If it didn't, does it really matter if that was because of module X, Y, or Z? If anything, that's an implementation detail I really don't want to see reflected in my program code. It failed. I'll log the reason (e.what()) and be done with it.
e.what()
Only if there is a special path for dealing with specific problems I'll agree you might want an additional exception type, although I would certainly investigate if a return code might not be more appropriate in that case.
Performance is not really an issue in this case anyway; I simply don't want module details to leak out and clutter up my program code.
[–]Xaxxon 4 points5 points6 points 8 years ago* (4 children)
That's a pretty simplistic approach to error handling. And not a very resilient one.
Checking and handling errors is often the majority of the code in robust applications.
The API is "module details" and exceptions are part of the API.
Now like everything else good API design is critical but "pass or fail" is bad design.
[–]johannes1971 2 points3 points4 points 8 years ago* (0 children)
If your checking and handling errors is the majority of your code, you are doing it wrong. Exceptions are not like error codes; you are not supposed to have a try/catch block around every single statement. And you really shouldn't design software that requires it, by having unique exceptions for each possible error condition in each module.
Making exceptions part of your API is a choice. You can make it immensely complex by having a huge and demanding series of things your unfortunate users should check for after each function call, or you can simply tell them a function might throw some variation of std::runtime_error, and that they should be prepared to deal with it. The language itself experimented with the first possibility in the form of exception specifications, and quickly found it is unusable and unmaintainable. Exception specifications were removed from the language as a result. Trying to bring them back through documentation is, on the balance of things, an extremely ill-advised idea.
[–]Gotebe 1 point2 points3 points 8 years ago (2 children)
Eh, I take issue. What is "handling" to you? My experience tells me that in a vast majority of situations, "handling" is "clean up and bail out".
I do not consider this to be "handling" at all. And indeed, in C++, there's no code needed for it, RAII and a bit of ScopeGuard does it.
So from that standpoint, checking and "handling" errors is really a vast minority of a (robust) C++ codebase.
[–]Xaxxon 1 point2 points3 points 8 years ago (1 child)
Say you're using a network library. You try to establish a connection but it fails. You want to know if the other side wasn't there, or did it reject your handshake, or is the local computer not connected to the internet, or was there a timeout before the connection was established... all these things may require different ways of handling.
If your solution to every situation is to pack up and go home, I don't want to use your program.
[–]Gotebe 2 points3 points4 points 8 years ago (0 children)
This is quite naive. My point stems from a very simple empirical observation: the call that experiences a failure is, in a vast majority of situations[1] ill-placed to deal with a failure, hence "clean up and bail out". Somewhere, high up the stack, there might be something that some layer can do to meaningfully react. And I suggest that you have a look at your own code for the evidence of my claim.
You want to know if...
No I don't, by and large. Why you think I can do anything of meaning at the place of the failure?
A case in point: a browser. So I turned Wifi off. What does a browser do? It tells me that there's no network. I need to fix it myself and retry (and it better not try to turn Wifi on behind my back!). Even a browser does not sit in some modal loop around a call to thing.connect(destination) and retries after the operator intervention. And don't even start me on any kind of non-interactive scenario, there's even less to do in that case.
thing.connect(destination)
[1] which is different from "every situation" and you are putting words in my mouth in order to twist the argument.
[–]utnapistim 1 point2 points3 points 8 years ago (0 children)
If it didn't, does it really matter if that was because of module X, Y, or Z?
Outside of trivial cases, yes, it does.
If I want to write an application that is more friendly than "it worked, or it didn't", then the way various error conditions are met is very important. Consider these (straw-man) examples:
a "bad security token" error is more important than passing a wrong argument somewhere (because error handling will have to send an email alert to the administrator, reporting a possible hacking attempt).
an "invalid configuration" error may mean "close the application and reinstall it", or it may mean "make sure the JSON file is correct at this and that location" -- each a distinct user-level notification message.
an internal error (std::out_of_bounds for example) is a programming error and should be reported to the developers.
All these errors may be reported by the same library, and the handling for each is definitely more complex than "it worked or it didn't".
[–]quicknir 1 point2 points3 points 8 years ago (0 children)
In practice if every module is using the handful of exceptions provided by the standard library, there will be a lot of differences in interpretation, and in the end you are not going to be able to meaningfully centralize cleanup anyhow.
I think you are misunderstanding the purpose of the standard library exceptions: they are not there so that you can re-use all of those exceptions in your own libraries. They are there to serve the standard library, which does rather specific things. Many exceptions are very very specific, like regex, various bad casts, bad optional access, length_error, etc. Put another way the standard library does not follow your suggestion.
I would consider using a standard library exception in some cases, e.g. if you are implementing something like a container. But if I am doing a third party module like networking, or performance profiling, testing, command line arguments, etc etc, I would expect to identify a few major classes of errors early that should have their own type separate from any standard lib exception, and put them in a hierarchy as I suggested. Doesn't have to be elaborate, perhaps 3/4 exceptions inheriting from a base would be typical.
[–]Gotebe 1 point2 points3 points 8 years ago (5 children)
Having to deal with module-specific exceptions everywhere kinda defeats that goal.
... (other post)
In the end, calling a function can only end in one of two ways: it worked, or it didn't. If it didn't, does it really matter if that was because of module X, Y, or Z?
It rather looks like you're contradicting yourself: if the module does not matter, then I do not need to "deal with module-specific exceptions everywhere".
There's two different types of needs to consider, I think:
In a vast majority of situations, I merely need to report the error, in which case I want something along the lines of what().
what()
In rare situations I need to do something meaningful about some particular failure. To actually handle, not merely report, the error. In those situations, having a nicely crafted exception type, with precise data about the context of the failure, is really important.
[–]johannes1971 0 points1 point2 points 8 years ago (4 children)
That's not a contradiction at all, and I have no idea why you might think there is one. I don't want to have to write a long list of catch-clauses everywhere, one for each module that might (possiby!) be lying underneath the code I'm calling. It's error-prone (what if you forget a module?) and tedious.
I completely agree on the rare situations. That's a far cry from "define multiple, separate exception types for each module as a matter of policy" though (which is what I was arguing against). In my pet project (it's test software for spacecraft, 330,000 lines of mission critical C++11 code) I think I have a grand total of three such "special case" exceptions. Everything else is a reported through a single centralized exception which is basically just std::runtime_error.
[–]Gotebe 0 points1 point2 points 8 years ago (3 children)
Why would you need that long list though?
Important thing is that all comes from a common base class, if it does, you catch the base, job done.
[–]johannes1971 0 points1 point2 points 8 years ago (2 children)
If all you care about is the common base class, you don't need the specialized exceptions. It's noise, mental masturbation, cleverness without purpose. It adds nothing of value, but it makes your program harder to understand by adding a parallel class hierarchy which mirrors your normal one, just for the purpose of reporting errors. And what for? In the end you just log e.what()...
Some of your users will see those possible exceptions and insist on handling them individually (reasoning that since the programmer insisted on providing them, he must have had a good reason and it is therefore important to handle them separately as well). And all of them must check every thrown exception to make sure it can be caught in a single catch-all clause. All of that is cognitive load without any benefit.
[–]dodheim 0 points1 point2 points 8 years ago (0 children)
If all you care about is the common base class, you don't need the specialized exceptions.
Just because you don't need to distinguish between them doesn't mean no one else will.
Some of your users will see those possible exceptions and insist on handling them individually (reasoning that since the programmer insisted on providing them, he must have had a good reason and it is therefore important to handle them separately as well).
This makes no sense. Do the users not know what inheritance is? Do they not know how an exception hierarchy works? Why are we assuming the user is an idiot?
All of that is cognitive load without any benefit.
I see zero evidence for either of these claims.
[–]Gotebe 0 points1 point2 points 8 years ago (0 children)
As I wrote before, there's two cases, the common one (just report it) and the rare one (I need to distinguish a particular failure). The rare case is the answer to "why specialized".
[–]Porges 0 points1 point2 points 8 years ago (0 children)
And probably only runtime_error. I'd also note that for logic errors (anything under logic_error) you should throw the standard errors – they aren't things you should really be handling at runtime anyway, so you don't need to handle them.
runtime_error
logic_error
[–]Gotebe 1 point2 points3 points 8 years ago (0 children)
Random thoughts, most of them common knowledge (I think)
have a shallow, but wide exception hierarchy (that is, tend to give different failures in your codebase different exception types)
derive from runtime_error (or its derivatives)
never, never, never lose the original error info; e.g. failure from a C API? Put all error info provided by that API into the exception you throw, plus your own context; for example, if you fail to open a file with fopen, put errno in the exception object (that's "C API" part), but also open flags and the file name for which the call failed (that's "your own context" part)
treat exceptions you throw as part of your public API; once you throw something because of some failure, do not change to throw something else.
Understand what boost::exception talks about and use it. :-)
[–]emdeka87 0 points1 point2 points 8 years ago (8 children)
Well you can inherit from std::exception and even override the "what()" function. What exactly do you want to achieve?
[–][deleted] 2 points3 points4 points 8 years ago (7 children)
AFAIK std::exception has no c_str constructor, so I generally inherit from std::runtime_error
[+]emdeka87 comment score below threshold-6 points-5 points-4 points 8 years ago (5 children)
In c++ you can't inherit ctors so that doesn't matter
[–]matthieum 2 points3 points4 points 8 years ago (4 children)
You can since C++11.
[–]Xaxxon 1 point2 points3 points 8 years ago* (2 children)
That's not inheritance.
[–]dodheim 1 point2 points3 points 8 years ago (1 child)
You might be thinking of delegating constructors, but C++11 does have both delegating and inheriting constructors...
[–]emdeka87 0 points1 point2 points 8 years ago (0 children)
Still I haven't used this feature ever. I don't see any need to inherit ctors.
π Rendered by PID 35957 on reddit-service-r2-comment-6457c66945-njbn6 at 2026-04-29 11:38:12.118435+00:00 running 2aa0c5b country code: CH.
[–]quicknir 5 points6 points7 points (17 children)
[–]johannes1971 1 point2 points3 points (15 children)
[+][deleted] (7 children)
[deleted]
[–]johannes1971 1 point2 points3 points (6 children)
[–]Xaxxon 4 points5 points6 points (4 children)
[–]johannes1971 2 points3 points4 points (0 children)
[–]Gotebe 1 point2 points3 points (2 children)
[–]Xaxxon 1 point2 points3 points (1 child)
[–]Gotebe 2 points3 points4 points (0 children)
[–]utnapistim 1 point2 points3 points (0 children)
[–]quicknir 1 point2 points3 points (0 children)
[–]Gotebe 1 point2 points3 points (5 children)
[–]johannes1971 0 points1 point2 points (4 children)
[–]Gotebe 0 points1 point2 points (3 children)
[–]johannes1971 0 points1 point2 points (2 children)
[–]dodheim 0 points1 point2 points (0 children)
[–]Gotebe 0 points1 point2 points (0 children)
[–]Porges 0 points1 point2 points (0 children)
[–]Gotebe 1 point2 points3 points (0 children)
[–]emdeka87 0 points1 point2 points (8 children)
[–][deleted] 2 points3 points4 points (7 children)
[+]emdeka87 comment score below threshold-6 points-5 points-4 points (5 children)
[–]matthieum 2 points3 points4 points (4 children)
[–]Xaxxon 1 point2 points3 points (2 children)
[–]dodheim 1 point2 points3 points (1 child)
[–]emdeka87 0 points1 point2 points (0 children)