How to quit, try {} catch {} should be used in the real world?

I mean, I knew all the language rules about throwing, try {} catch {}, but I'm not sure if I use them correctly in the real world. See the following example:

We have a big piece of scientific code that did all kinds of image processing, recently we decided to pick it up and make it more reliable. One commonly used routine is void rotate_in_place (float * image, image_size sz) ;

To make it more reliable, add some health check at the beginning of the code:

void rotate_in_place(float* image, image_size sz) { // rotate_in_place does not support non-square image; if (sz.nx != sz.ny) throw NonSquareImageError; // rotate_in_place does not support image too small or too large if (sz.nx <= 2 || sz.nx > 1024) throw WrongImageSizeError; // Real rode here ..... } 

Now the problem is that rotate_in_place () is used in over 1000 places, I have to wrap every call to rotate_in_place () with try {} catch {}, it looks like the code will be incredibly bloated. Another possibility is not to wrap up any attempt to {} catch {} and exit the program, but how is this different from using

 if (sz.nx != sz.ny) { cerr << "Error: non-squared image error!\n"; exit(0); } 

In short, I am not so sure of the real benefits of using throws, attempts, catches, good offers?

+6
source share
8 answers

Each site that handles the error requires a try - catch . It all depends on your design, but I doubt that you need to handle the error on each rotate_in_place call rotate_in_place , you probably avoid spreading up most of the time.

Printing errors and using exit bad for three reasons:

  • You cannot handle the error. exit does not process (if this is not done when the error is absolutely critical, but your function cannot know that - the caller may have a way to recover).
  • You extend the responsibilities of the write function to hard code that may not even be available (it's rotate_in_place , not rotate_in_place_and_print_errors_and_kill_the_program_if_something_is_wrong ) - it hurts to be reused.
  • You lose all debugging information using this approach (you can generate stack traces from unhandled exceptions, you can do nothing with the function that is called every time - the unhandled exception is an error, but it is an error with which you can follow the source).
+6
source

The general rule for exceptions is: "Does the site immediately call what is happening here?" If the call site takes care, then it probably makes sense to return a status code. Otherwise, throwing makes sense.

Think of it this way - of course, your rotate in place method has a couple of invalid argument types, in which case you should probably throw away std::invalid_argument . It is unlikely that the caller of rotate_in_place wants to deal with or knows how to deal with the fact that the image was not square, for example, and therefore is probably better expressed as an exception.

Another possibility is not to wrap any try {} catch {}, and let the program exit, but how is this different from using

 if (sz.nx != sz.ny) { cerr << "Error: non-squared image error!\n"; exit(0); } 

This is different in that if someone later wants to take your function and put it, say, in a graphical application, they do not need to interrupt the program based on the error. They can turn this exception into something user-friendly or something like that.

It also has advantages for you right now, namely that you do not need to drag <iostream> into this translation block just to record errors.

I usually use a template like this:

 int realEntryPoint() { //Program goes here } int main() { //Allow the debugger to get the exception if this is a debug binary #ifdef NDEBUG try #endif { return realEntryPoint(); } #ifdef NDEBUG catch (std::exception& ex) { std::cerr << "An exception was thrown: " << ex.what() << std::endl; } #endif } 
+5
source

Now the problem is that rotate_in_place () is used in more than 1000 places, I have to wrap every call to rotate_in_place() with try{} catch {} , it will look very badly bloated.

It will, and it beats the goal of using exceptions in the first place.

Another possibility is not to wrap any try {} catch {} and not exit the program, but how it differs from using only [...]

That you can change the location of the exception handling later. If at some point you find the best place for a reasonable elimination of the error (possibly recovering from it), then in the place where you put the catch . Sometimes this is in the very function where you throw the exception; sometimes this happens in a call chain.

Put a catch -all in main , just in case. std::runtime_error out standard exceptions like std::runtime_error makes this a lot easier.

+4
source

The point of use for exception handling is in the following simple rules:

  • As soon as something bad can happen due to incorrect user input (internal logic should be processed through statements / logging), throw an exception. Throw as soon as possible and as much as possible: C ++ exceptions are usually quite cheap compared to, say, .Net.
  • Let the exception be thrown if you cannot handle the error. It almost always means.

Keep in mind the following: an exception must bubble to such an extent that it can be handled. This may mean a dialog box with some formatting of the error, or it may mean that some non-essential part of the logic will not be executed in the end, etc.

+3
source

Using exceptions allows the caller to decide how to handle the error. If you called exit directly inside the function, the program would exit without the caller deciding how to handle this error. In addition, upon exit stack objects will not be unwound.: - (

+1
source

What you can do is make rotate_in_place return a boolean if the function call was successful. And return the rotated image using the function parameter.

 bool rotate_in_place(float* image, image_size sz, float** rotated_image) { // rotate_in_place does not support non-square image; if (sz.nx != sz.ny) return false; // rotate_in_place does not support image too small or too large if (sz.nx <= 2 || sz.nx > 1024) return false; // Real rode here ..... return true; } 
+1
source

It depends.

Exceptions are usually intended to be captured / handled. In your case, is it possible to handle the exception (for example, the user provides a non-square image, so ask them to try again). However, if you can't do anything about it, then cerr is the way to go.

0
source

Well, I agree that really using Exceptions leads to bloated code. This is the main reason why I do not like them.

In any case, as for your example: the key difference between exception exceptions and just using the exit () function is that since the exception is handled (or should happen) outside the fragment of the program that generated the error / exception, you will not specify how the user of the function / class should handle the error. Using exceptions, you allow various procedures, such as interrupting a program, reporting errors, or even recovering from certain errors.

TLDNR: If you use exceptions, the part of the code that generates the exception should not indicate how the exception is handled. This happens in an external program and can be changed depending on how the code is used.

0
source

Source: https://habr.com/ru/post/898448/


All Articles