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,
mpl::map
) ?file_not_found
or disk_error
, re-run the function with a different file)?Thanks
Additional to what nogard said I want to add the following:
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With