I am writing some library functions that needs to do some error reporting. I want to use exceptions rather than return values.
I wrote my functions that throws int exceptions.
Eg:
if(strm->atEnd()){
// unexpected end of stream
throw -2;
}
My question is, is this method OK? Or should I throw a exception derived from std::exception?
In what way is throwing a std::exception better? (Other than being able to use catch(std::exception &e))
Is throwing int exceptions bad practice? (all throw int values are documented in doxygen comments)
I can't find any reason as to why (in this case) should I throw an object.
I would throw an exception based on std::exception.
throw std::runtime_error("unexpected end of stream")
I find this easier to catch, log, et cetera. It also allows the removal of a comment and a magic number from the code.
This message can then be sent to the end-user to give them a hope of fixing the problem.
Users and library consumers can't read the comments in code, and they are unlikely to know what '-2' means.
Exception are for exceptional behaviour. They're the last thing that you should worry about optimizing!
Donald Knuth said:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil
Also, an object as exception may carry information about the error.
For example, you have an exception that means that a file cannot be read. If you throw an object exception, the object may carry the file name, which you cannot have with ints.
If the exception origin is unknown (deep in your stack) and no one catches it, it will be easier to debug the program if the exception is an object with proper information.
My question is, is this method OK?
Think about the readability. Wouldn't
throw CUnexpectedEndOfStream();
be more readable than
throw -2
?
And in a lot of cases wouldn't seeing an instance of CUnexpectedEndOfStream thrown in the debugger mean TONS more than -2. That's not to mention that CUnexpectedEndOfStream could store gobs of useful information about the problem such as say the file that couldn't be read and maybe more info on the nature of the problem.
Or should I throw a exception derived from std::exception?
Inheriting from std::exception may be helpful if that's how you choose to organize your other exceptions. It a convenient base class that client code can use. Also depending on the exception you may want to use std::runtime_error.
Is throwing int exceptions bad practice? (all throw int values are documented in doxygen comments)
Who said it was bad practice? Throwing exceptions is a great way to handle exceptional situations. Most of the exceptions I throw are because of something that could have been prevented by the client code doing what it was supposed to-- the user of my code violated the contract. But many other exceptional non-normal cases also exist like OS errors, disks filling up, etc. All the things that aren't part of your programs normal flow. More importantly, since they're not part of your program's normal flow, you don't need to worry about performance.
As an example, I once used exceptions to trigger that a certain message parsing failure occurred. However, I found that these parsing errors occurred frequently to the point where I started handling exceptions and fixing the problem input and reparsing. After a while, I realized that a more readable solution would be to fix the problem directly in the parsing code and stop treating it like an exceptional case. All the code that made parsing decisions was put back in one place and I wasn't throwing exceptions like a drunken sailor throws out curse words.
You should throw an exception derived from std::exception, e.g. std::runtime_error.
Most existing code assumes that an ordinary C++ exception is a std::exception, and anything else is a "hard exception" to be propagated up to a very high control level, like main.
For example, existing code will most probably not be able to log any reasonable message for your int. It will just be "unknown exception type".
Cheers & hth.,
Why don't you do this:
if(strm->atEnd()){
// unexpected end of stream
throw std::exception("-2");
}
throw -2 is bad because the type of -2 is neither std::exception nor derives from std::exception.
Or you should better write your own class as:
class FileException : public std::exception
{
//...
};
And then
throw FileException("Unexpected end of stream");
which is more readable.
Related
I've been reading about exceptions in C++, the pros and cons, and I've yet to encounter anyone mention the two things I really like about them: They allow me to extend the definition of an error (to something that is more than just an error message as a string), and, they allow me to define a contract between the exception handler and the thrower:
"If I'm going to handle this particular type of error, I'm going to
need this, this and that from you."
I've not seen this mentioned in any of the articles, forums and blog posts, as a pro or a con. And that has made me suspect that my mindset on exceptions and how they should be used may be wrong.
To clarify, here's an example of my usage of exceptions:
A program communicates with a USB device (it sends commands to the device and expects a certain response from it). This USB device can sometimes behave in an unexpected way when responding to a command. In this case, the program will throw an UnexpectedResponseFromDevice exception. The handler for this exception needs more than just an error message in order to do its job. For example, it may need to know of the command that we were sending to the device when the error occurred, and/or the state the device was in. I use the definition of my UnexpectedResponseFromDevice class to explicitly set out what is required to handle the exception. See below for a rough idea.
class UnexpectedResponseFromDevice : public std::exception
{
private:
Command command;
DeviceState deviceState;
std::string msg;
public:
UnexpectedResponseFromDevice(std::string msg, Command command, DeviceState deviceState, ...)
Command getCommand();
DeviceState getDeviceState();
};
This is what I meant by "define a contract between the exception handler and the thrower". In order to throw the exception, these things (in this case a Command, a DeviceState and a message) need to be provided.
Is this an acceptable use case for exceptions? Is it OK for me to store this other information, that is required for the handling of the exception, in the exception object? Is it acceptable but a bad idea? If so, please explain why.
Is this an acceptable use case for exceptions? Is it OK for me to store this other information, that is required for the handling of the exception, in the exception object?
Yes, that's how the exceptions in the standard library do too. One example is std::system_error that derives from std::runtime_error but adds a std::error_code member to carry extra information. One that adds a lot more is std::filesystem::filesystem_error that adds two std::filesystem::path objects.
Is it acceptable but a bad idea? If so, please explain why.
It's only a bad idea if you risk throwing another exception (like a std::bad_alloc) while throwing your exception - or if you use exceptions as something else than exceptions, like choosing between common branches in your program flow. Throwing should preferably be a rare event.
If your have all the info you need in a std::string, or even in something like a std::stack<std::string>>, member variable in the object that is a about to throw you can probably std::move that member object into the exception object to minimize the risk - if you don't need that data anymore in the object that is throwing that is.
I don't know how big your std::string, Command and DeviceState objects are, but you may not want to construct the exception object by taking the parameters by value. Try to make construction noexcept. The getters should also probably return by const&. That's not as critical - but making them so minimizes the risk of an exception in your exception handler.
Yes, a parameter is handed over. By means of it information is made available.
catch(const exception& e) { e....; }
I recently learned that in C++ there is a single "slot" for an active exception and this raise some questions for me.
The example that I know is something like:
void f()
{
MyClass c;
throw MyException;
}
When we get to the throw the function immediately returns and then the exception starts looking for its matching catch. But let's say that during the return of f, when the destructor of c is called, suppose it throws another exception of type MyException2, in this case from what I understood the program always crashes because there is only one "slot" for an active exception so when MyException2 occurs there is a problem.
I would like to know if there is a reason for this specific approach since most other languages have some sort of stack and give a message like During handling of this exception this other exception occurred, with clear stack traces for both exceptions.
Is there a reason for this problem not being approached? Things like a stack of active exceptions and if MyException2 occurs while MyException1 is active then it will just resolve and then return to the handling of MyException1?
I'm sorry if I may not be familiar with the proper terms, this is a purely education question from someone who wishes to know more about the "guts" of the language out of pure fascination.
What you’re thinking about in, say, Python looks like
try: risky()
except Error as e:
some_cleanup(e)
also_risky() # raises OtherError
if still_unhappy(): raise
more_handling()
The corresponding code in C++ behaves the same way and does not automatically terminate:
try {risky();}
catch(const Error &e) {
some_cleanup(e);
also_risky(); // throws OtherError
if(still_unhappy()) throw;
more_handling();
}
The reason is that the original exception might or might not have been handled successfully (is more_handling necessary, or is it just part of retrying?). C++ makes the optimistic statement that it was, whereas by default Python 3 makes the pessimistic statement that the new exception is fallout from the old. C++ could of course provide a syntax to indicate the other choice, like Python does (raise new from None), but such an “associated exception” would be more difficult still to deal with in a static-typing context than exceptions already are, and one of the main motivations is absent since C++ expects the program to provide whatever backtrace-reporting mechanisms are desired.
The parallel is stronger if you consider destructors in both languages (especially in CPython where many of them are reliably invoked during stack unwinding): here, Python simply prints to standard error if a destructor throws, because to do otherwise would greatly complicate its internal resource management. C++ is actually more permissive in that a destructor can throw so long as it was not invoked directly by the unwinding mechanism; this is dangerous, but is occasionally used by experts to good effect. On the other hand, C++ most certainly does not consider writing to standard error a sufficient option for handling an exception, so if its resource management encounters such a problem, it’s all over.
Say I'm using a library that has a function to_int that takes a string parameter. This function returns an int if the string is a character representation of a number, e.g "23" would return 23. If the string isn't a number it throws an std::runtime_error. Would it be better to:
if(is_all_digits(str))
x = to_int(str);
else
output("not an int, idiot. Try again");
Or
try
{
x = to_int(str);
}
catch(...)
{
output("not an int, idiot. Try again");
}
There are several different error handling techniques and each have advantages and disadvantages.
Lets consider a function getAllElements() which gets a container with some elements.
Now this may produce an error (database connection or whatever). You now have the options
Errorcode getAllElements(std::vector<...> & cont);
or
std::vector<...> getAllElements(); //throws exceptions
It is kind of a general design question usually and depends on circumstances. I prefer the one with the exceptions for multiple reasons. I can just assign and don't need a predetermined container
auto elements = getAllElements();
The next thing is where will you handle your errors? If you handle them like 5 functions above in the stack you have to check for the error-code every time and just give it to the next function. An exception will automatically propagate until someone catches it and is able to deal with it.
Exceptions though have some disadvantage. They cause a bigger binary and is slower when an exception gets thrown. In game development usually no exceptions are used because of that ( Listen to this for more info on that: http://cppcast.com/2016/10/guy-davidson/ they talk about why not using exceptions. I don't have the timestamp currently though. )
Also exceptions should be used in exceptional cases. Errors you cannot deal with immediately and have to be dealt with somewhere higher.
So if you don't need high performance / a small binary I would suggest using exceptions where they are useful. They can result in typing less code (like checking return codes) which can result in less places for introducing bugs.
Here is also a good discussion on error handling mechanisms from CppCon 2016:
CppCon 2016: Patrice Roy “The Exception Situation"
There is no single answer to this question, as it depends on how the program as a whole can deal with bad input, and whether it can sensibly recover when errors are detected (regardless of whether those errors are reported using return codes or by throwing exceptions).
Can every function which calls to_int() recover from bad input immediately? If not, it is better to allow an exception to be thrown .... so it unwinds the stack until there is some caller (with a try/catch block) that can actually recover from the error.
What if you have numerous functions that call to_int(), do you want to do the check in every one? If so, this results in a lot of code duplication.
What if you have some function that calls to_int() which can recover immediately from the error and some others that cannot?
What if you want to report an error to the caller (e.g. to allow something more substantial than writing an error string)?
What is there is no is_all_digits() function? If there is not, what if you implement it in a way that misses some errors that to_int() will detect? Then you have the worst of both worlds - doing the error checking in an attempt to prevent an exception being thrown, but then the function throwing an exception anyway. For example, there might be some global setting that causes to_int() to only accept octal digits (in range 0 to 7), but your is_all_digits() function deems all decimal digits to be valid.
More generally, the real need is to define an error handling strategy that works for your program as a whole. Trying to decide, based on usage of a single function, between throwing exceptions or not throwing exceptions, is completely missing the point.
If it makes sense for your program to report errors using exceptions (e.g. with a single centralised try/catch block in main() so all errors propagate up the call stack so main() implements the recovery globally) then throw exceptions. If it makes sense for every function in your program to detect errors and silently deal with them on the spot, then avoid exceptions.
What I'm advocating is allow the dog (your program) to wag the tail (low level decisions on how to handle errors). Your question is essentially asking if it is appropriate to allow the tail to wag the dog.
If the caught exception is really specific than you can use a specific try catch (using a generic try catch is not a good idea since you are hiding a bunch of other possible errors)
Generically speaking my preference is to check the string before passing it to the function.
When you are using a library or an API you want it to prevent you from bad usages and other mistakes.
This is the role of your function to control the integrity of the given parameters, and to throw an exception.
Note that you can also use assertions when developing your code, and then disable it for binary production.
Should my exception classes provide details in public fields in addition to what()?
Consider for example boost::property_tree::ptree_bad_path which might give a message:
"No such node (mynode.value1)"
The only way to access the path ("mynode.value1") is by parsing the string. Is there an argument against adding additional public fields to carry such information, that is:
class ptree_bad_path : public ptree_error {
public:
const std::string path; // <- additional detail by public field
....
Are there drawbacks to this approach?
In theory, you run the risk of having your program terminate if you ever have two unhandled exceptions at the same time. This is, however, a rather rare situation.
Throwing during the preparation of the exception: fine (though you won't get the exception you expected)
Throwing during the copy of the exception (often elided, avoidable): crash
Throwing during the unwinding: crash
Throwing during the handling of the exception (catch): fine (after all, rethrowing a different exception is common)
So, the avoidable risk here is if the copy constructor of your exception might happen to throw. It is trivial to elude the issue by moving the state off to a shared_ptr contained within the exception. It makes copies a bit "special" (since they share their state with the original) but if it's documented properly it should not cause any grief.
The greater risk is during stack unwinding. It only occurs if a destructor throws, though.
Personally, the exceptions I use contain:
an error code (for the API to display/encode properly, all error messages are mapped to a code, it helps in Chinese/Korean/Japanese, really)
a log message, with some details (ID/name of the item that cause the issue, original error when translating another exception, whatever helps!)
the function/file/line at which the exception was thrown
the time at which the exception thrown
additional notes (appended "on the fly" during stack unwinding)
a complete backtrace (using Linux specific functions)
The only controversial point here is the on the fly bit, since it might effectively crash. On the other hand, I work on servers so crashes are easily (and urgently) fixed and for the last 5 years I was careful enough not to cause a crash (this way ;)).
Note that this scheme is obviously only available if you use exceptions sparsely. If you routinely throw a dozen exceptions per task, the performance might be unnacceptable. On the other hand, the Zero Cost model used by major compilers already harshly penalize the exceptional path so...
Your exception class should contain all the information required to handle the error. This usually means tagging it with what went wrong and any context necessary. It is a good idea to store the path in your exception class.
Are there drawbacks to this approach?
Try to avoid having the members themselves throw as they will call std::terminate.
This is just my opinion, but if you're going to throw an exception you might want to make sure it has enough information for you to know (a) what caused the exception, and (b) where the exception was thrown.
You are probably (hopefully) not going to show the exception to the end user, so therefore logging the exception becomes something that purely enables/improves supportability. So from a development perspective, you basically want to be in a position where you know as much as possible about what happened.
Of course you're right in that you are walking a fine wire here. You don't want to have such complex code in your exception handling that it runs the risk of throwing its own exception!
Your exceptions may carry as much information as their catchers are ready (and willing) to use. If your particular application can use this additional information, you can write your own exception classes with peace of mind. In any case, all exception classes should inherit from std::exception to ensure that catch clauses not expecting custom exceptions will work correctly.
A different issue is exposing those classes on a library to be used by third party clients. In this case you should consider carefully whether the benefits of this additional information outweight the hassle introduced by the additional interface and even the possibility that it may not be used at all.
EDIT: As Pubby says, your exception classes should never throw to avoid unwelcome calls to std::terminate(). In general, no exception-related code should ever throw, and this includes destructors for any class.
It seems it is general accepted that exception specifications are not helping as much as one thinks. But I wonder if a specification which only uses std::exception might be a good compromise:
void someFunction()
throw ( std::exception );
It documents the fact that this method/function might throw an exception.
It would make sure that only exceptions derived from std::exception are thrown and not some exotic classes like std::string or int.
So, would this be better then not having any specification at all?
Update:
Regarding the Runtime-Overhead: Think of it like the usage of asserts. You are using asserts regardless of the runtime-overhead, right? I know you usually can disable them for a release-build, so maybe a better approach would be to wrap the exception specification in a macro so you can disable it for a release build. Something like:
#ifdef DEBUG
#define THROW( exception ) throw ( exception )
#else
#define THROW( exception )
#endif
void someFunction()
THROW( std::exception );
Yes but what do you expect to happen when something that is not derived from std::exception is thrown?
Would you like the application to terminate.
No stack unwinding not destructors being called to tidy up the code, just the application exiting.
The difference between Java and C++ exception specifications is that Java checks the specifications at compile-time. C++ on the other hand does all the checking at run-time. So by the time your specifications have been violated it is already too late.
Even in Java code there is a movement to stop to using them. What tends to happen there is at the start of the project the exception specifications are tightly defined. But as the code grows and becomes more complex the specifications are diluted to a more and more general form. This is because as the code grows more exceptions can be thrown and if they can not be handled immediately you need to modify the exception specifications of the whole call chain back to the point where they can be handled. (Note I am not a Java Expert but I do play in a mature Java code base).
The only exception specification (I think) that is worth much is the no throw specification. This does have a valid application (but you have to use it with the try/catch(...) block).
Also read Herb Sutters article:
And this thread on SO: Should I use an exception specifier in C++?
Exception specifications are essentially useless. Martin York already linked to Herb Sutter's post about them, but in short, you run up against the following problems:
They're ignored by MSVC, and
Their effect is nothing like in
Java. The specifications are checked
at runtime, causing a performance
hit, witout giving you the
compile-time validation you get in
Java. All you're saying is "Insert extra code, such that when an
exception is thrown, its type is inspected, and then
either throw it as normal, or call
unexpected() instead.
So all you're doing is making it harder to catch the exceptions that may be thrown, while at the same time slowing down your program. There really isn't much point.
On a conforming compiler, adding a non-empty exception specification generates the equivalent of a try/catch block around the function. Although it's possible to implement this in a way that has no run-time overhead, on some current compilers you do get an overhead.
So there may be a cost, and all you gain is that, if someFunction or something it calls raises on non-std::exception-derived exception, std::unexpected is called, rather than the unhandled exception mechanism.
So I guess my answer's 'No' :-)
I tipically would do this:
void someFunction() /* throw (std::exception) */;
The only effect of the throw statement in the function declaration is to modify its signature: a pointer to "void x()" and a pointer to "void x() throw y" are two different types.
In this way you are still documenting that the function might throw something, and you are losing nothing since the c++ compiler does not enforce any constraint anyway.