Re: [boost] [boost::exception] operator >>

Emil Dotchevski <emildotchevski@gmail.com> wrote:
hello! i'm using boost::exception in one project and did small modification for myself, what do you think about it ?
i don't want to create a lot of exception classes, because my 'catches' will use only a few of them anyway. but while exception is throwing, some functions add different information to it (with operator <<) that is useful in diagnostic messages.
so when we decide to extract that information from exception, we need to study what useful information it has. instead of using if-else it'll be nice to use inheritance of _errors_ (not exceptions), for example:
throw our_exception () << error_1 (); ... catch (our_exception & e) { re-throw e << error_2 (); } ... catch (our_exception & e) { shared_ptr <base_of_error_1_and_2> ptr; while (e >> ptr) cout << ptr->format_error_message(); }
I understand what you are doing but I don't understand why. Could you provide a non-abstract example of a use case that benefits from this addition?
No problem. We have to basic exception classes: errors associated with external files or system calls and internal interpreter errors. To work properly, program don't need a lot of information about errors, but we need this information in error messages. boost::exception gives simple way to collect error context so each function does not need to worry about errors it catches, but should just add its context. In result, content of exception depends on it path throw function and modules. A few pieces of code (i omit boring parts): struct silent : virtual exception { inline silent (guid_t e) : exception (e) {} }; struct critical : virtual exception { inline critical (guid_t e) : exception (e) {} }; template <typename level> struct system_error : public level { inline system_error (guid_t e) : exception (e), level (e) {} }; struct info { virtual void printf (boost::format &) const = 0; virtual guid_t format (void) const = 0; virtual ~info () {} }; // in RL we generate them using boost macros :) struct module_info_e : public info { guid_t format (void) const { return 101; } void printf (boost::format & dest) const { const boost::tuple < string, string > & tuple = static_cast < const boost::error_info< module_info_e, boost::tuple <string, string> > *> (this) -> value(); dest % tuple.get<0>() % tuple.get<1>() ; } }; typedef boost::error_info < module_info_e, boost::tuple < string, string
module_info ; enum { bad_module };
....... // in Module::arch_dependent::load throw system_error <silent> (bad_module); ..... // in Module::load catch (silent & e) { throw e << module_info (make_tuple ("1.so", "error while loading")); } ..... // in Script::run that can run command that loads module (or not, we don't know) catch (silent & e) { throw e << context_info (make_tuple (current_line)); } ..... // some function that should be stable catch (exception & e) { print_error (e); } print_error() is a point where we should discover exception content. In above example it is like this: ostringstream message; for (boost::shared_ptr <info const> base ; e >> base ; ) { boost::format format (Sys::Instance().Reader <Resources> :: get <char_t*> (base->format ( ))); // get format string for error base->printf (format); // fill format string with error info content message << format << std::endl; } If we use exception hierarchy instead of error information hierarchy we don't have such freedom like this (using virtual functions) because we can't combine error information so random. So it is main purpose -- to avoid worrying about what errors we are catching). Also IMHO it is not too beautiful because a lot of functions shouldn't know anything about error information, only about exceptions, so they should be separated. I don't insist on this, just report changes that I need for myself. I'm sorry i'm too verbose (or sorry if i'm not verbose enough :)
participants (1)
-
Gaydov Victor