What is the common use of exceptions on a catch site?

My understanding of exception handling is very limited. Although I find it easy to throw an exception (or I can pack it with expected<T> for later consumption), I know very little about what to do with the exception.

Currently my knowledge is limited

  • clear my own resources and rebuild the exception that will be handled in the appropriate place. eg.

     ptr p = alloc.allocate(n); try { uninitialized_copy(first,last,p);//atomic granularity, all or none } catch(...) { alloc.deallocate(p,n); throw; } 

But, I think it can be equivalently converted to a RAII pattern as

 alloc_guard<ptr> p{alloc.allocate(n)}; uninitialized_copy(first,last,p.get()); p.commit(); 
  • catch the exception at the top level, compose and print a nice message and exit.eg

     int main(int argc,char** argv) { try { app_t the_app(argc,argv); the_app.run(); } catch(std::runtime_error& e) { //instead of what, I can also compose the mesage here based on locale. std::cout<<e.what()<<std::endl; } } 

So, everything I do is in a top-level function, for example main , catches the exception and prints the corresponding message and closes.

When implementing a library with a good set of APIs that uses various external libraries as the back end for implementation, I realized that third-party library exceptions are part of my API specification as they cross my library boundary and fit into user code!

So, in my library API all exceptions from external libraries are registered (and each of them has its own hierarchy of exceptions), which I used for the user code.

This leads to my question, that everything can be done when I catch any exception?

More specific,

  • Is it possible to translate a caught exception from an external library into my own exception and throw it in a general way (say, a comparison between the hierarchy of exceptions of third-party libraries and my exception API is provided as mpl::map )?
  • Can I do something more useful than printing a message / call stack, say, resuming a function on a throw site with a different input parameter (say, when I get this file_not_found or disk_error , re-run the function from another file)?
  • Any other template worth knowing?

thanks

+6
source share
3 answers

This is a very big question.

  • I doubt that you can easily translate third-party exceptions into your own exceptions, and, moreover, I personally do not see the need to implement this behavior. Since a third-party library is part of your implementation that is not exposed to the public API, why would you expose all its exceptions (even through some mapping)? If one day you stick to another third-party library that implements the same things - do you want to reverse engineer the entire hierarchy of exceptions? I think no. Your library's API should not be fragile, so I would suggest that you do not map external exceptions to your own.

  • You can map third-party exceptions to your hierarchy in the following ways:

    • Do not wrap anything. I mean, you don’t have to drop anything because the 3rd library does this. You can catch this exception and handle it, or return an error code, or change the state accordingly. There are many other possibilities, rather than retroning always.

    • You do not need to do one-to-one translations for all third-party exceptions. If you use the AAA library internally, then you can have one AAAException representing many exceptions coming from this library.

  • Good to know: always catch exceptions using the const link:

    catch (const exception & ex)

This question is very big, I hope that my answer will help to understand it.

Replies to comments:

  • If I do not correlate third-party exceptions with my own API (not necessarily one to one), they flow to the client code. No, they don’t do it, that’s all! You have to catch them in your library and then decide what to do with the catching exceptions: throw your own exception, return an error code, notify the client listener, a journal error, etc.

     try { 3rdpatry.call(); } catch (const 3rdpartyException & ex) { // throw YourException(ex.what()); // listener.notify(some_error) // return some_code } 
  • Capturing with the const link does not mean that you don’t cut the slices at all. There is a pleasant discussion here that explains this.

+1
source

In addition to what nogard said, I want to add the following:

  • Exceptions should be used for exceptional things. Things that should not happen.
  • If you encounter an exception, write it down at least somewhere. This may help you find the error.
  • Try to resolve the error in the place where you found the exception.
  • If this is not possible, try to stay in a state in which the application can continue.
  • If this is not possible - think about a competent conclusion.
  • Let the user know that something unusual has happened.

Final tip - Combine error handling. This includes translating exceptions from third-party libraries into your exception hierarchy.


Replies to comments:

2) The exception should contain information about what went wrong. It can be only type or additional information. Registration of this data with the client allows you to get additional information about what actually went wrong as required by the client. Perhaps he used your application incorrectly, found another use case, or you just have an error (for example, an uninitialized variable). But with this additional information, you have a place where something went wrong, and some information about what went wrong. This will help you identify the source of the error and therefore find the error.

3) it actually depends on the error that occurs. For instance. you are trying to access a configuration file that is not -> you are creating a new one with default values. The client tries to open the database for write access, but is write protected. You refuse to open, return to the correct state and tell the client that db is write protected. You have run out of memory and cannot continue? Write this down (beware - you don’t have free memory, so your log should already reserve some memory in advance for this use case) and gracefully close the application. Perhaps, if possible, inform the customer.

As for the code from other libraries: there is no other way to check every function call in another library for exceptions that it could return and catch them. After you are caught, you can transfer information from this exception to one of yours and throw this exception (or allow it somehow otherwise)

+3
source

Top-level catch is usually not enough for large applications. You need to catch the exception if you can do something about it, but there are only a few ways to do it with the exception:

  • Recover if you can. - (for example: Check for updates → Could not open network connection exception → ignore and do not download the update now.)
  • Tell the user how to recover it. (for example: Save file -> File cannot throw an exception -> instruct the user to select a different file name or cancel)
  • Entrance and exit. This is the most complex top-level scenario.
+1
source

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


All Articles