|
Boost : |
From: Emil Dotchevski (emil_at_[hidden])
Date: 2007-10-01 14:19:55
> <snip>
> No, not my point. It's about increasing the expressiveness of client
> code: It provides means for a user to express: "I'm going to throw a
> bunch of exceptions (starting) with common attributes. Please give me a
> brief way to create them, so error reporting doesn't obscure my code."
>
> It also allows to easily port "traditional" exception classes to
> boost::exception.
>
> Further it would allow to allocate the attributes of a custom_exception
> in one shot.
Yes, I think I understand your point, but...
> > So, I'd write that function like this:
> >
> > void read_file( char const * filename )
> > {
> > try
> > {
> > something_unrelated();
> > ....
> > if( file_failure )
> > throw file_error();
> > }
> > catch( boost::exception & x )
> > {
> > x << error_info<tag_filename>(filename);
> > throw;
> > }
> > }
> >
> > How would your custom_exception idea fit in this framework?
>
> So now you're bringing up a different use case.
... I'm bringing up the different use case because -- at least in my
experience -- it is very common when using boost::exception; I'm
trying to convince the audience that the effort to bundle multiple
pieces of data together perhaps isn't as beneficial as one hopes,
because a lot of times all you have is a single piece of data that is
relevant to a failure.
Please bear with me for one more example :)
shared_ptr<FILE> open_file( char const * name, char const * mode )
{
if( FILE * f=fopen(name,mode) )
return shared_ptr<FILE>(f,fclose);
throw file_open_error() <<
error_info<tag_file_name>(name) <<
error_info<tag_open_mode>(mode) <<
error_info<tag_errno>(errno);
}
void read_file( shared_ptr<FILE> const & f, std::vector<char> & buf )
{
....
size_t s=file_size(f);
if( s>max_size )
throw file_too_big_error() <<
error_info<tag_file_size>(s) <<
error_info<tag_max_file_size>(max_size);
....
}
void parse_data( char const * data, size_t s )
{
....
if( parse error )
throw parse_data_error() <<
error_info<tag_parse_error_code>(15) <<
error_info<tag_parse_error_offset>(offset) <<
erorr_info<tag_parse_buffer>(std::string(data,s));
....
}
void parse_file( char const * name )
{
shared_ptr<FILE> f=open_file(name,"rt");
try
{
std::vector<char> buf;
read_file(f,buf);
parse_data(&buf[0],buf.size());
}
catch( boost::exception & x )
{
x << error_info<tag_filename>(name);
throw;
}
}
Though this code is far from being complete, parse_file can emit the
following exceptions already:
file_open_error
file_too_big_error
parse_data_error
If we make this example complete, the list will be longer still.
In my mind, it makes no sense to bundle tag_file_name, tag_open_mode,
and tag_error together (which, if I understand is what you were
thinking), because they appear together in only one exception:
file_open_error.
On the other hand, tag_file_name is relevant to any failure occuring
within parse_file. We shouldn't worry about what else might be
relevant, or how to bundle it -- we just stuff in the exception
whatever is known to us. In particular, note that parse_data doesn't
deal with files at all; it can't possibly "bundle" a file name in the
parse_data_error exception, but at the same time if the data came from
a file, we don't ever want that particular parse_data_error to reach a
catch without a file name.
Emil Dotchevski
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk