0

I'm writing a function, wd_sprintf, to provide a sprintf-like API. Under the covers, it uses the boost library.

If the user of wd_sprintf codes the format string improperly, boost::format will throw an exception. I'd like for my function to intercept the exception, repackage it in a message that identifies wd_sprintf as the locus of the error, and rethrows the exception.

What I can't figure out is what to catch, and how to extract the message.

// wd_sprintf(pattern [,args...]):                                                                                                                                              
//                                                                                                                                                                              
// This creates a temporary boost::format from pattern, and calls                                                                                                               
// wd_sprintf_r() to recursively extract and apply arguments.                                                                                                                   
#include <boost/exception/all.hpp>
class wd_sprintf_exception : std::runtime_error {
public:
    wd_sprintf_exception(string const& msg : std::runtime_error(msg) {}
};

template <typename... Params>
string
wd_sprintf (const string &pat, const Params&... parameters) {
    try {
        boost::format boost_format(pat);
        return wd_sprintf_r(boost_format, parameters...);
    }
    catch (boost::exception e) {
        const string what = string("wd_sprintf: ") + string(e.what());
        throw wd_sprintf_exception(what);
    }
}

Of course, this gets a compilation error because boost::exception is abstract.

(I've been to a number of sites and pages, including this one whose title was similar but which was full of '<<' operators inserting into a function call, template constructs like boost::get_error_info<my_tag_error_info>(e), and generally much more complexity than I suspect is really needed. I just need the above to work.)

Community
  • 1
  • 1
Chap
  • 3,649
  • 2
  • 46
  • 84
  • 2
    You should always be [catching by reference](http://stackoverflow.com/questions/2023032/catch-exception-by-pointer-in-c). `boost::exception` (and the C++ standard library) were designed this way. – Jesse Good Feb 26 '14 at 03:33

1 Answers1

0

You can't have an an automatic variable of an abstract type. You can, however, have a reference or pointer to one. The reason for this is that the compiler has no way of knowing exactly which derived type the variable actually is, so it doesn't know how much space to allocate for it or which class's copy constructor to use.

When you catch a boost::exception by value, as you're doing, the compiler has to make a local copy of it in your catch block; which it doesn't have enough information to do!

In your specific case, the best solution is to catch a reference to the original exception.

In regards to catching exceptions from Boost.Format, it throws exceptions derived from boost::io::format_error, which is derived from std::exception, not boost::exception. You should be catching boost::io::format_error.

Collin Dauphinee
  • 13,664
  • 1
  • 40
  • 71
  • That is helpful, and catching by reference did away with the compiler error. But I still don't know how to extract a message out of **e**. (`e.what()` doesn't work because `boost::exception` doesn't have `what()` ) – Chap Feb 26 '14 at 03:53
  • Still isn't working quite right. I've now changed it to `catch (boost::io::format_error& e) {` and everything else is the same, including `throw wd_sprintf_exception(what);` (`wd_sprintf_exception` is derived from `std::runtime_error`.) The client wraps his call to wd_sprintf with `try { ... }` `catch (std::runtime_error& e) {` `cout << e.what() << endl;}`. The exception isn't caught; instead I abort with uncaught exception of type wd_sprintf_exception. – Chap Feb 26 '14 at 06:17
  • However, if -- instead of `throw wd_sprintf_exception(what);` -- I simply write `throw;`, my uncaught exception message says **terminating with uncaught exception of type boost::exception_detail::clone_impl >: boost::bad_format_string: format-string is ill-formed**, which at least is the text I'm after! – Chap Feb 26 '14 at 06:22