Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it better to check values before passing to a library function, or catch a thrown exception?

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");
}
like image 636
NeomerArcana Avatar asked Oct 18 '16 08:10

NeomerArcana


People also ask

When should you use exceptions C++?

Use exceptions when the code that handles the error is separated from the code that detects the error by one or more intervening function calls. Consider whether to use error codes instead in performance-critical loops, when code that handles the error is tightly coupled to the code that detects it.

Does throw exit the function C++?

throw usually causes the function to terminate immediately, so you even if you do put any code after it (inside the same block), it won't execute. This goes for both C++ and C#.

Is exception handling in C++ cheap?

Modern C++ implementations reduce the overhead of using exceptions to a few percent (say, 3%) and that's compared to no error handling. Writing code with error-return codes and tests is not free either. As a rule of thumb, exception handling is extremely cheap when you don't throw an exception.

What is C++ try block?

The try statement allows you to define a block of code to be tested for errors while it is being executed. The throw keyword throws an exception when a problem is detected, which lets us create a custom error. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.


2 Answers

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"

like image 90
Hayt Avatar answered Oct 16 '22 23:10

Hayt


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.

like image 20
Peter Avatar answered Oct 17 '22 00:10

Peter