15

Please tell me how to use try/catch properly with boost::exception.

This is one of examples

void Settings::init(const std::string &filename)
{
    using boost::property_tree::ptree;
    try 
    {
        read_xml(filename, pt);
    }
    catch(boost::exception const&  ex)
    {
        LOG_FATAL("Can't init settings. %s", /* here is the question */);
    }
}

Do I need catch std::exception too? I can't let my application fail, so I just need to log everything.

UPD: I also can't understand now to retrive information for logging from exception???

SoapBox
  • 20,457
  • 3
  • 51
  • 87
nix
  • 464
  • 1
  • 5
  • 13
  • 2
    Yes, I would add std::exception too, right after boost::exception. I would also add catch (...) – kol Nov 15 '11 at 12:51
  • 9
    If an exception is thrown because an error occurred, then simply catching the exception does not eliminate the error. Your application still fails, you've just made it harder to see what's going on. So only catch exceptions if you can know what they indicate, and can meaningfully handle them – jalf Nov 15 '11 at 12:53
  • 1
    @jalf The above code did not simply swallow the exception. There is some logging at least. – kol Nov 15 '11 at 12:55
  • @kol: didn't it? Unless `LOG_FATAL` terminates the application, it just logs a message, and then discards the exception and continues as if nothing had happened. – jalf Nov 15 '11 at 12:56
  • @jalf Neither of us know, what `LOG_FATAL` does exactly... anyway you are right :) – kol Nov 15 '11 at 12:59
  • 1
    Guys =) this is not so crucial now. you'd better tell me about UPD – nix Nov 15 '11 at 13:02
  • 1
    UPD? What's UPD? And I think in a question about how to properly catch exceptions, discussing how exceptions should be caught us pretty crucial. ;) – jalf Nov 15 '11 at 13:46

5 Answers5

13

std::exception has a member function called what() that returns a const char* that might explain what happened. If you want to log it (guessing that LOG_FATAL wraps printf somehow) you can do:

catch(std::exception const&  ex)
{
    LOG_FATAL("Can't init settings. %s", ex.what());
}

For boost::exception though you can use boost::get_error_info to find out more about it.

Community
  • 1
  • 1
Flexo
  • 87,323
  • 22
  • 191
  • 272
  • 2
    Although to access `what()` from a `boost::exception`, you'll need to either catch, or `dynamic_cast` to, `std::exception`. – Mike Seymour Nov 15 '11 at 13:57
  • 5
    Unless I'm mistaken, boost::exception doesn't inherit from std::exception, so your example that calls .what() on it is invalid. Also, I believe std::exception usually returns a const char* rather than a std::string – obmarg Nov 15 '11 at 14:00
  • @obmarg You're mistaken. `catch(boost::exception const& e){ cout << dynamic_cast(e).what(); }` compiles and works perfectly. – Qix - MONICA WAS MISTREATED Jan 27 '14 at 11:25
  • 2
    @Qix I don't do enough C++ these days to investigate, but certainly looks like `booost::exception` doesn't inherit from `std::exception`: http://www.boost.org/doc/libs/1_55_0/libs/exception/doc/boost_exception_exception_hpp.html – obmarg Jan 27 '14 at 11:51
  • 1
    @Qix Ah, of course. Shame it doesn't seem to be documented obviously anywhere (though to be fair I'm not looking very hard) – obmarg Jan 27 '14 at 12:19
10

probably WAY too late in answering... but

        <...snip...>
        catch (const boost::exception& e)
        {
            std::string diag = diagnostic_information(e);
            // display your error message here, then do whatever you need to, e.g.        
            LOG_FATAL("Can't init settings. %s", diag);
        }
        <...snip...>
cincodenada
  • 2,877
  • 25
  • 35
Mia Shani
  • 121
  • 1
  • 8
5

As with any C++, the following universal rule applies:

Catch all exceptions that can possibly be thrown, and only if you can respond to them meaningfully.

You can catch all other exceptions (...) as well and create a log message or something like that, but then you have to rethrow them (throw;). If there's nothing you can do in your code other than abort some operation, then you don't need to handle the exception. Let it bubble up to a place where it can be used meaningfully.

In your code, you will have to allow at least for memory allocation errors (std::bad_alloc), so you could check for those, if that makes sense. But again, if you don't know what you're catching, there's not much you can do with what you catch.

Saying your "program cannot fail" can only mean so much. Ultimately, if you have an allocation error in a top-level data structure, there's nothing you can do. The best scenario I can imagine is if your main function processes some data in a loop; in that case, you can put a universal try block around the loop, and in case of an exception you just move on to the next round. But I would count that as an instance of being able to "handle an exception meaningfully", so that's just a special case of the above. In general, while you may want to wrap your entire main function in a try block, you'll just have to accept that in the ultimate catch-all case you don't have much of a choice but to abort the program.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

That depends on the code that you're running in the try block. If the code in read_xml could throw a std::exception then you would be better to catch std::exception as well. If you're unsure, then it can't really hurt to catch both of them.

obmarg
  • 9,369
  • 36
  • 59
0

You should catch only special exception types if you really want to do something related to that type. Otherwise just use std::exception. If you're code could throw something different, than catch ... instead or after std::exception.

If you want to handle multiple (special) exception types than you need to handle the most explicit first.

0xbadf00d
  • 17,405
  • 15
  • 67
  • 107