How to make an intelligent decision about which standard exception to throw? - c++

We know that the exception class has two derived classes: logic_error and runtime_error.
logic_error has four derived classes: domain_error, invalid_argument, length_error and out_of_range.
runtime_error has three derived classes: range_error, overflow_error and underflow_error.
While some of them are self-explanatory, like overflow_error and underflow_error, some are not that clear, especially range_error, both MSDN and cplusplus just say "to report a range error", which is close to saying nothing, how it is different out_of_range and domain_error???
Another question is when I throw an exception, which one should I choose? For example, In reverse_string(char* s), which exception to throw when s is NULL? In float calc_ellipse_area(float a, float b), which to throw when a or b is <=0? Which to throw when a == b (strictly speaking, circle is not an ellipse!)?
Finally, practically speaking, does it really matter if I throw an exception which is not correctly categorized?

A logic error is the (theoretically) result of a programmer error.
A runtime error is something that could not easily have been prevented by the programmer.
When you write a function, it is useful to document its preconditions and/or assumptions. If those preconditions are broken, it is a logic error.
A runtime error is usually due to something external: a file operation failed, a printer is offline, a DLL could not be loaded.
If a path parameter is malformed, that is a logic error. If it is a valid path string, but does not exist, or you don't have permission to access it, that is a runtime error.
Sometimes it becomes arbitrary. Bad user input is probably a runtime error, but failure to validate user input is more of a logic error. It may not be obvious which is the case in a particular situation.
If something starts in 01 Feb 2011, a finish date of "01 Jan 2011" is an invalid argument, while "31 Feb 2011" is out of range. A finish date of "fish and chips" is a domain error. Length errors are often about buffer size, but that might also include too much or too little input data or something like that.
A range error is similar to an out of range error, except for the context (runtime, not logic). e.g. Number of printers available = 0. Overflow and underflow are more or less self-explanatory.
In the end, use them in a way that you and your colleagues find meaningful -- or possibly don't use them at all. Some people just use std::exception for everything.
It is only really important if you are going to handle different exceptions differently. If you are just going to display (or log) a message and carry on, it doesn't matter what exception(s) you use.

For example, In reverse_string(char* s), which exception to throw when s is NULL?
In float calc_ellipse_area(float a, float b), which to throw when a or b is <=0? Which to throw when a == b (strictly speaking, circle is not an ellipse!)?
For both of these, use std::invalid_argument.
Or you can define your own exception called null_argument deriving from std::logic_error (or from std::invalid_argument), and use it for NULL argument.
The point is that if none of the standard exception class applies to your situation, or you want more specific exception, then define one deriving from existing classes.
For example, if you want to throw exception when you encounter an invalid index, then either you can use std::out_of_range or define more specific class called index_out_of_range deriving from std::out_of_range.
does it really matter if I throw an exception which is not correctly categorized?
Yes, it does matter. For example, it increases readability of your code. If you throw std::logic_error when an invalid index is encountered, then well, it doesn't add much to the readability, but instead of that if you throw std::out_of_range , then it greatly increases the readability. And if you throw index_out_of_range, it increases even more, as it's more specific.

From the standard:
The Standard C++ library provides classes to be used to report certain errors (17.6.5.12) in C++ programs. In the error model reflected in these classes, errors are divided into two broad categories: logic errors and runtime errors.
The distinguishing characteristic of logic errors is that they are due to errors in the internal logic of the program. In theory, they are preventable.
By contrast, runtime errors are due to events beyond the scope of the program. They cannot be easily predicted in advance.
However, all the exception types derived from runtime_error are misclassified -- all of them are easily preventable.
For actual runtime errors, the C++ standard library is rather inconsistent, it sometimes uses return values or internal state (e.g. iostream::bad(). And when it does use exceptions, they don't derive from runtime_error. For example, std::bad_alloc is a direct subclass of std::exception.
In conclusion, you shouldn't ever use std::runtime_error or any of its predefined subclasses.

The difference between out_of_range and range_error is found in the description of their parent classes:
logic_error: This class defines the type of objects thrown as exceptions to report
errors in the internal logical of the program. These are theoretically
preventable.
runtime_error: This class defines the type of objects thrown as exceptions to report
errors that can only be determined during runtime.
Domain error is for mathematical functions specifically. So your calc_ellipse_area could quite sensibly throw a domain error on negative value (and return 0 if one or both arguments are 0). I don't see any reason to complain if the ellipse happens to also be a circle, any more than a rectangle area function should fail on a square.
Passing null pointers to functions that shouldn't receive NULL I would handle by invalid argument exceptions.
C++ lets you throw whatever you like. What's really helpful to those who might use your code is that you name what you throw after the method signature, and that these names are reasonably descriptive. By default, a function could throw anything - to promise that a function won't throw, you have to use an empty throw() in the signature.

Related

Is the `std::exception`, in its current form, redundant?

Usually, when I want to create my own exception, I inherit from std::exception or std::runtime_error.
Is there anything that stops me from creating my own empty "tag-class"?
class out_of_bounds_access {}; // or:
class memory_leak {};
and throw just that?
After all, mostly, it's the class-name that carries information about what went wrong not the members of the exception class.
Ok, so I assumed this is a bad idea, but why? Why is this a bad idea?
P.S. I know there are cases in which "custom-made" exceptions carry information that latter is used to determine the correct approach to solve the problem...
However, if you think about it, cases like that can, very often (not always, but often), be re-done to throw & catch multiple different tag-classes instead of just a single one (with "content").
No, nothing stops you from doing this.
However, some code that wants to catch "any exception" will catch const std::exception&, and if your exception type doesn't derive from std::exception then that won't work.
Sure, we can catch ... instead but that's, in my experience, used as a last-ditch "blunt instrument" for avoiding termination due to uncaught exceptions, and can't tell you anything about the exception itself.
Boost exceptions don't derive from std::exception and it's really annoying.
Why not just make all the exceptions part of this standard hierarchy?
If you don't intend to ever let your exception types make get all the way to the top, then there may not be a practical problem here. But, why take the chance? You lose nothing by adding : std::runtime_error or somesuch, and the text string that you'll pass to the base is useful information for the diagnosing programmer.

How to design exception "types" in C++ [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Two anti-patterns that are incredibly common in most code bases I've worked out of are Boolean return values to indicate success/failure, and generic integral return codes to indicate more details about an error message.
Both of these are very C-like and do not fit into C++ very well in my humble opinion.
My question is in regards to best practices when it comes down to designing exceptions into your code base. In other words, what is the best way to indicate the finite possibilities for failure? For example, one of the aforementioned anti-patterns would typically have one giant enumeration with each enumeration value representing a specific kind of failure, such as FILE_DOES_NOT_EXIST or NO_PERMISSIONS. Normally these are kept as general as possible so that they can be used across multiple, unrelated domains (such as networking components and file I/O components).
A design similar to this that one might consider for exceptions is to subclass one concrete exception type from std::exception for each type of failure or thing that might go wrong. So in my previous example, we would have the following:
namespace exceptions {
class file_does_not_exist : public std::exception {};
class no_permissions : public std::exception {};
}
I think this is closer to something that "feels better", but in the end this just seems like a maintenance nightmare, especially if you have hundreds of these "error codes" to translate over into classes.
Another approach I've seen is to simply use the standard <stdexcept> classes, such as std::runtime_error and have a string with the specifics. For example:
throw std::runtime_error( "file does not exist" );
throw std::runtime_error( "no permissions" );
This design is much more maintainable but makes it difficult or unfeasible to conditionally catch either of these exceptions should they both be potentially thrown from the same core location or function call.
So what would be a good, maintainable design for exception types? My requirements are simple. I'd like to have contextual information about what happened (did I run out of memory? Do I lack filesystem permissions? Did I fail to meet the preconditions of a function call (e.g. bad parameters)?), and I'd also like to be able to act on that information accordingly. Maybe I treat all of them the same, maybe I have specific catch statements for certain failures so I can recover from them differently.
My research on this has only lead me to this question:
C++ exception class design
The user here asks a similar question that I am, and his/her code sample at the bottom is almost likable, but his/her base exception class does not follow the open/closed principle, so that wouldn't really work for me.
The C++ standard library’s exception hierarchy is IMHO pretty arbitrary and meaningless. For example, it would probably just create problems if anyone started actually using e.g. std::logic_error instead of terminating when it’s clear that the program has a Very Nasty Bug™. For as the standard puts it,
“The distinguishing characteristic of logic errors is that they are due to errors in the internal logic of the program.”
Thus, at the point where it might otherwise seem reasonable to throw a std::logic_error the program state might be unpredictably fouled up, and continued execution might put the user’s data in harm’s way.
Still, like std::string the standard exception class hierarchy has a really really practically important and useful feature, namely that it’s formally standard.
So any custom exception class should be derived indirectly or (although I would not recommend it) directly from std::exception.
Generally, when the debates about custom exception classes raged ten years ago, I recommended deriving only from std::runtime_error, and I still recommend that. It is the standard exception class that supports custom messages (the others generally have hardcoded messages that one preferably should not change, since they have value in being recognizable). And one might argue that std::runtime_error is the standard exception class that represents recoverable failures (as opposed to unrecoverable logic errors, which can’t be fixed at run time), or as the standard puts it,
“runtime errors are due to events beyond the scope of the program. They cannot be easily predicted in advance”.
Sometimes the C++ exception mechanism is used for other things, treated as just a low-level dynamic destination jump mechanism. For example, clever code can use exceptions for propagating a successful result out of a chain of recursive calls. But exception-as-failure is the most common usage, and that’s what C++ exceptions are typically optimized for, so mostly it makes sense to use std::runtime_error as root for any custom exception class hierarchy – even if that forces someone who wants to be clever, to throw a “failure”-indicating exception to indicate success…
Worth noting: there are three standard subclasses of std::runtime_error, namely std::range_error, std::overflow_error and std::underflow_error, and that contrary to what their names indicate the latter two are not required to be be generated by floating point operations and are not in practice generated by floating point operations, but are AFAIK only generated by some – surprise! – std::bitset operations. Simply put, the standard library’s exception class hierarchy seems to me to have been thrown in there just for apperance’s sake, without any real good reasons or existing practice, and even without a does-it-make-sense check. But maybe I missed out on that and if so, then I still have something new to learn about this. :-)
So, std::runtime_error it is, then.
At the top of a hierarchy of custom exception classes, with C++03 it was useful to add in the important stuff missing from C++03 standard exceptions:
Virtual clone method (especially important for passing exceptions through C code).
Virtual throwSelf method (same main reason as for cloning).
Support for chained exception messages (standardizing a format).
Support for carrying a failure cause code (like e.g. Windows or Posix error code).
Support for getting a standard message from a carried failure cause code.
C++11 added support for much of this, but except for trying out the new support for failure cause codes and messages, and noting that unfortunately it’s pretty Unix-specific and not very suitable for Windows, I haven’t yet used it. Anyway, for completeness: instead of adding cloning and virtual rethrowing (which is the best that an ordinary application programmer can do in a custom exception class hierarchy, because as an application programmer you cannot hoist a current exception object out of the storage that the implementation’s exception propagation uses), the C++11 standard adds free functions std::current_exception() and std::rethrow_exception(), and instead of support for chained exception messages it adds a mixin class std::nested_exception and free functions std::rethrow_nested and std::rethrow_if_nested.
Given the partial C++11 support for the above bullet points, a new and modern custom exception class hierarchy should better integrate with the C++11 support instead of addressing the C++03 shortcomings. Well, except for the C++11 failure code thing, which seems to be very unsuitable for Windows programming. So, at the top of the custom hierarchy, right under std::runtime_error, there will ideally be at least one general exception class, and derived from that, one exception class that supports propagation of failure codes.
Now, finally, to the gist of the question: should one now best derive a unique exception class for every possible failure cause, or at least for major failure causes?
I say no: DON’T ADD NEEDLESS COMPLEXITY.
If or where it is can be useful for a caller to distinguish a certain failure cause, a distinct exception class for that is very useful. But in most cases the only information of interest to a caller is the single fact that an exception has occurred. It is very rare that different failure causes lead to different attempted fixes.
But what about failure cause codes?
Well, when that's what an underlying API gives you, it is just added work to create corresponding exception classes. But on the other hand, when you are communicating failure up in a call chain, and the caller might need to know the exact cause, then using a code for that means the caller will have to use some nested checking and dispatch inside the catch. So these are different situations: (A) your code is the original source of a failure indication, versus (B) your code uses e.g. a Windows or Posix API function that fails and that that indicates failure cause via a failure cause code.
I have used boost::exception for a while now and I really like inserting arbitrary data into an exception.
I do this in addition to specific exception types, e.g.
#define MY_THROW(x) \
BOOST_THROW_EXCEPTION(x << errinfo_thread_id(boost::this_thread::get_id()))
class DatabaseException : public std::exception, public boost::exception { ... };
typedef boost::error_info< struct errinfo_message_, std::string > errinfo_message;
MY_THROW(DatabaseException(databaseHandle)
<< boost::errinfo_api_function("somefunction")
<< errinfo_message("somefunction failed terribly.")
);
This way you can catch specific exceptions while also providing loads of detail from the throw site (e.g., file name, line number, thread id, ...).
It also provides some pretty printing of the exception message and its details.
Most of the time I write that information in my log and abort the program, depending on the exception.
EDIT: As noted in the thread you cited, use shallow hierarchies. I use something like 3-4 exception classes that inherit directly from std::exception and boost::exception. I also put lots of details into the exceptions (e.g., the thread id).
If the error condition is something that caller of your library could have prevented by changing logic of their code then derive your exception from logic_error. Generally, caller won't be able to do simple retry if logic_error is thrown. For example, someone is calling your code such that it would cause divide by 0 then you may create custom exception,
class divide_by_zero : public logic_error {
public:
divide_by_zero(const string& message)
: logic_error(message) {
}
}
If the error condition was something that could not have been prevented by the caller then derive from runtime_error. Some of these errors might be recoverable (i.e. caller can catch exception, re-try or ignore).
class network_down : public runtime_error {
public:
network_down(const string& message)
: runtime_error(message) {
}
}
This is also the general philosophy to design exceptions in standard library. You can view the exception code for GCC here.

When throwing different kinds of exceptions is useful?

Is it useful to throw different exceptions for instance std::runtime_error or std::invalid_argument in huge projects? Or is it better to throw in general std::exception with a good text parameter for what()? And when does it make sence to derive some sub classes from std::exception?
Rumo
It always makes sense to use throw the most specific exception. As each exception should be derived from std::exception the code catching may decide at which level of granularity it wants to handle it (catch by reference! Item 13 in "More effective C++" from S. Meyers).
Using only std::exception with only some text a no-go:
unnecessary limiting the usage possibility of the catching code
the catching code would need to parse the text to base logic on if it had to perform different actions depending on the type of exception (whihc can be realized at lower cost with RTTI)
I cannot think of any case where it would be benefitiable to do so. Overriding what() provides an adequate text for any exception if you need.
I'd say that having a well thought hierarchy of exceptions is better than having only a single exceptions' type distinguished by its error message. This because you could write code like this:
try {
object.method();
}
catch (LogicalException& e) {
// if it's a LogicalException, handle it here
}
catch (Exception& e) {
// otherwise, handle a general exception here.
}
where LogicalException is-an Exception. Writing code like this in the other way would result in a long serie of if-else, very error-prone if you ask me.
All the Standard C++ exception classes are derived from the class std::exception. So, the catching code might catch the exception in std::exception & or with the specific clas handler but it makes more sense to throw the specific exception, so that the appropriate handler can handle the specific exception.
While I agree in principle that
It always makes sense to use throw the most specific exception
it may or may not be necessary.
I wrote the framework for a huge project and at first I was all gung ho on designing the mother of all error reporting systems -- it was gonna be beautiful. Part of the design was a hierarchy of exception classes.
And I chucked it all out. Not because it was bad, I chucked it because it was totally unnecessary.
We handled the existing exceptions of course, but there was no need for more than one custom exception because, as it turned out, every one of our "exceptional conditions" was what I call a "programmer" error, essentially a failed assertion.
The best solution in our case was a system which logged a discriptive trail of breadcrumbs to a file and then displayed the equivalent of "oops, sorry!" at the next appropriate idle state along with a link to tech support.
That was our app. Perhaps you are writing a library, in which case ignore everything I just said.
So -- sorry this sounds like a cop out -- but the answer to your question is:
It depends.

Should I inherit from std::exception?

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?
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.
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.
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.
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.
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.
Yes you should derive from std::exception.
Others have answered that std::exception has the problem that you can't pass a text message to it, however it is generally not a good idea to attempt to format a user message at the point of the throw. Instead, use the exception object to transport all relevant information to the catch site which can then format a user-friendly message.
The reason why you might want to inherit from std::exception is because it allows you to throw an exception that is caught according to that class, ie:
class myException : public std::exception { ... };
try {
...
throw myException();
}
catch (std::exception &theException) {
...
}
There is one problem with inheritance that you should know about is object slicing. When you write throw e; a throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw. That could be not what you're expecting. Example of problem you could find here.
It is not an argument against inheritance, it is just 'must know' info.
Difference: std::runtime_error vs std::exception()
Whether you should inherit from it or not is up to you. Standard std::exception and its standard descendants propose one possible exception hierarchy structure (division into logic_error subhierarchy and runtime_error subhierarchy) and one possible exception object interface. If you like it - use it. If for some reason you need something different - define your own exception framework.
Whether to derive from any standard exception type or not is the first question. Doing so enables a single exception handler for all standard library exceptions and your own, but it also encourages such catch-them-all handlers. The problem is that one should only catch exceptions one knows how to handle. In main(), for example, catching all std::exceptions is likely a good thing if the what() string will be logged as a last resort before exiting. Elsewhere, however, it's unlikely to be a good idea.
Once you've decided whether to derive from a standard exception type or not, then the question is which should be the base. If your application doesn't need i18n, you might think that formatting a message at the call site is every bit as good as saving information and generating the message at the call site. The problem is that the formatted message may not be needed. Better to use a lazy message generation scheme -- perhaps with preallocated memory. Then, if the message is needed, it will be generated on access (and, possibly, cached in the exception object). Thus, if the message is generated when thrown, then a std::exception derivate, like std::runtime_error is needed as the base class. If the message is generated lazily, then std::exception is the appropriate base.
Since the language already throws std::exception, you need to catch it anyway to provide decent error reporting. You may as well use that same catch for all unexpected exceptions of your own. Also, almost any library that throws exceptions would derive them from std::exception.
In other words, its either
catch (...) {cout << "Unknown exception"; }
or
catch (const std::exception &e) { cout << "unexpected exception " << e.what();}
And the second option is definitely better.
If all your possible exceptions derive from std::exception, your catch block can simply catch(std::exception & e) and be assured of capturing everything.
Once you've captured the exception, you can use that what method to get more information. C++ doesn't support duck-typing, so another class with a what method would require a different catch and different code to use it.
Though this question is rather old and has already been answered plenty, I just want to add a note on how to do proper exception handling in C++11, since I am continually missing this in discussions about exceptions:
Use std::nested_exception and std::throw_with_nested
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace 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 benefit I see in subclassing (instead of just using std::runtime_error) is that your exception handler can catch your custom exception and do something 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;
}
Another reason to sub-class exceptions is a better design aspect when working on large encapsulated systems. You can reuse it for things such as validation messages, user queries, fatal controller errors and so on. Rather than rewriting or rehooking all of your validation like messages you can simply "catch" it on the main source file, but throw the error anywhere in your entire set of classes.
e.g. A fatal exception will terminate the program, a validation error will only clear the stack and a user query will ask the end-user a question.
Doing it this way also means you can reuse the same classes but on different interfaces. e.g. A windows application can use message box, a web service will show html and reporting system will log it and so on.

C++ exception class design [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
What is a good design for a set of exception classes?
I see all sorts of stuff around about what exception classes should and shouldn't do, but not a simple design which is easy to use and extend that does those things.
The exception classes shouldn't throw exceptions, since this could lead straight to the termination of the process without any chance to log the error, etc.
It needs to be possible to get a user friendly string, preferable localised to their language, so that there's something to tell them before the application terminates itself if it can't recover from an error.
It needs to be possible to add information as the stack unwinds, for example, if an XML parser fails to parse an input stream, to be able to add that the source was from a file, or over the network, etc.
Exception handlers need easy access to the information they need to handle the exception.
Write formatted exception information to a log file (in English, so no translations here).
Getting 1 and 4 to work together is the biggest issue I'm having, since any formatting and file output methods could potentially fail.
EDIT:
So having looked at exception classes in several classes, and also in the question Neil linked to, it seems to be common practice to just completely ignore item 1 (and thus the boost recommendations), which seems to be a rather bad idea to me.
Anyway, I thought I'd also post the exception class I'm thinking of using.
class Exception : public std::exception
{
public:
// Enum for each exception type, which can also be used
// to determine the exception class, useful for logging
// or other localisation methods for generating a
// message of some sort.
enum ExceptionType
{
// Shouldn't ever be thrown
UNKNOWN_EXCEPTION = 0,
// The same as above, but it has a string that
// may provide some information
UNKNOWN_EXCEPTION_STR,
// For example, file not found
FILE_OPEN_ERROR,
// Lexical cast type error
TYPE_PARSE_ERROR,
// NOTE: in many cases functions only check and
// throw this in debug
INVALID_ARG,
// An error occured while trying to parse
// data from a file
FILE_PARSE_ERROR,
}
virtual ExceptionType getExceptionType()const throw()
{
return UNKNOWN_EXCEPTION;
}
virtual const char* what()throw(){return "UNKNOWN_EXCEPTION";}
};
class FileOpenError : public Exception
{
public:
enum Reason
{
FILE_NOT_FOUND,
LOCKED,
DOES_NOT_EXIST,
ACCESS_DENIED
};
FileOpenError(Reason reason, const char *file, const char *dir)throw();
Reason getReason()const throw();
const char* getFile()const throw();
const char* getDir ()const throw();
private:
Reason reason;
static const unsigned FILE_LEN = 256;
static const unsigned DIR_LEN = 256;
char file[FILE_LEN], dir[DIR_LEN];
};
Point 1 is addressed since all strings are handled by copying to an internal, fixed size buffer (truncating if needed, but always null terminated).
Although that doesn't address point 3, however I think that point is most likely of limited use in the real world anyway, and could most likely be addressed by throwing a new exception if needed.
Use a shallow hierarchy of exception classes. Making the hierarchy too deep adds more complexity than value.
Derive your exception classes from std::exception (or one of the other standard exceptions like std::runtime_error). This allows generic exception handlers at the top level to deal with any exceptions you don't. For example, there might be an exception handler that logs errors.
If this is for a particular library or module, you might want a base specific to your module (still derived from one of the standard exception classes). Callers might decide to catch anything from your module this way.
I wouldn't make too many exception classes. You can pack a lot of detail about the exception into the class, so you don't necessarily need to make a unique exception class for each kind of error. On the other hand, you do want unique classes for errors you expect to handle. If you're making a parser, you might have a single syntax_error exception with members that describe the details of the problem rather than a bunch of specialty ones for different types of syntax errors.
The strings in the exceptions are there for debugging. You shouldn't use them in the user interface. You want to keep UI and logic as separate as possible, to enable things like translation to other languages.
Your exception classes can have extra fields with details about the problem. For example, a syntax_error exception could have the source file name, line number, etc. As much as possible, stick to basic types for these fields to reduce the chance of constructing or copying the exception to trigger another exception. For example, if you have to store a file name in the exception, you might want a plain character array of fixed length, rather than a std::string. Typical implementations of std::exception dynamically allocate the reason string using malloc. If the malloc fails, they will sacrifice the reason string rather than throw a nested exception or crashing.
Exceptions in C++ should be for "exceptional" conditions. So the parsing examples might not be good ones. A syntax error encountered while parsing a file might not be special enough to warrant being handled by exceptions. I'd say something is exceptional if the program probably cannot continue unless the condition is explicitly handled. Thus, most memory allocation failures are exceptional, but bad input from a user probably isn't.
Use virtual inheritance. This insight is due to Andrew Koenig. Using virtual inheritance from your exception's base class(es) prevents ambiguity problems at the catch-site in case someone throws an exception derived from multiple bases which have a base class in common.
Other equally useful advice on the boost site
2: No you should not mix user interface (=localized messages) with program logic.
Communication to the user should be done at an outer level when the application
realises that it cannot handle the issue. Most of the information in an
exception is too much of an implementation detail to show a user anyway.
3: Use boost.exception for this
5: No dont do this. See 2. The decision to log should always be at the error handling site.
Dont use only one type of exception. Use enough types so the application can
use a separate catch handler for each type of error recovery needed
Not directly related to the design of an exception class hierarchy, but important (and related to using those exceptions) is that you should generally throw by value and catch by reference.
This avoids problems related to managing the memory of the thrown exception (if you threw pointers) and with the potential for object slicing (if you catch exceptions by value).
Since std::nested_exception and std::throw_with_nested have become available with C++11, I would like to point to answers on StackOverflow here and here
Those answers describe how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
The exception design there, in my opinion, also suggests to not create exception class hierarchies, but to only create a single exception class per library (as already pointed out in an answer to this question).
A good design is not to create a set of exception classes -
just create one per library, based on std::exception.
Adding information is fairly easy:
try {
...
}
catch( const MyEx & ex ) {
throw MyEx( ex.what() + " more local info here" );
}
And exception handlers have the information they need because they are exception handlers - only the functions in the try blocks can cause exceptions, so the handlers only need to consider those errors. And not you should not really be using exceptions for general error handling.
Basically, exceptions should be as simple as possible - a bit like logfiles, which which they should have no direct connection.
This has been asked before, I think, but I can't find it right now.