Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the common usage of exceptions at catch site?

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

Presently my knowledge is limited to

  • clean my own resources and rethrow the exception to be handled at appropriate location. e.g.

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

But I guess, this can be equivalently transformed in a RAII pattern as

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

    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, all I do is in a top level function such as main catch the exception and print an appropriate message and close.

While implementing a library with a nice set of API using various external libraries as back end for implementation, I realized that third party library exceptions are part of my API specification, as they cross my library boundary and land in user code!

So, my library API leaked all exceptions from external libraries (and each one having their own exception hierarchy) that I was using to the user code.

This leads to my question, what all can be done when I catch any exception ?

More specifically,

  • Can I translate the caught exception from external library to my own exception and throw that in a generic way (say the mapping between third party library exception hierarchy and my exception API is provided as a mpl::map) ?
  • Can I do something more useful than printing a message/call stack, say resume the function at the throw site with different input parameter (say when I get that a file_not_found or disk_error, re-run the function with a different file)?
  • Any other pattern which is valuable to know?

Thanks

like image 662
abir Avatar asked Aug 13 '13 04:08

abir


1 Answers

Additional to what nogard said I want to add the following:

  1. Exceptions should be used for exceptional things. Things that should not happen.
  2. If you encounter an exception, log it at least somewhere. This might help you finding a bug.
  3. Try to resolve the error at the point where you caught the exception.
  4. If this is not possible, try to stay in a consistent state where the application can continue.
  5. If this is not possible - think about gracefully terminating.
  6. Notify the user that something out of the ordinary happened.

Final advice - keep your error handling consistent. This includes translating exceptions from third party libraries to your exception hierarchy.


Answers to comments:

2) The exception should contain information about what went wrong. This could be just the type or some additional information. Logging these at the customer allows you to get more information on what actually went wrong beyond to what the customer tells you. Perhaps he misused your application, found another use case or you simply have a bug (e.g. a not initialized variable). But with this extra information you have a location where something went wrong and some information on what went wrong. This helps you to deduce the source of the error and thus find the bug.

3) this actually depends on the error that is occurring. E.g. you try to access a configuration file that is not there --> you create a new one with default values. The client tries to open a database for write access, but it is write protected. You decline opening, return to a valid state and tell the client that the db is write protected. You run out of memory and can't continue? Log this (beware - you have no spare memory so your logging should already have reserved some memory upfront for this use case) and gracefully shut down the application. Perhaps, if possible, notify the client.

Regarding code from other libraries: there's no other way then checking each function call to another library for the exceptions it might return and catching them. Once caught, you can transfer the information from that exception into one of yours and throw that exception (or resolve it somehow else)

like image 94
Tobias Langner Avatar answered Nov 14 '22 21:11

Tobias Langner