Boost logo

Boost Users :

Subject: Re: [Boost-users] [Test] Making use of boost::exception_diagnostic_information and friends
From: Emil Dotchevski (emildotchevski_at_[hidden])
Date: 2009-08-10 18:54:09


On Mon, Aug 10, 2009 at 2:58 PM, Gennadiy Rozental<rogeeff_at_[hidden]> wrote:
> Emil Dotchevski wrote:
>> I was implying that you normally catch more specific exceptions first.
>> If you don't care about foo in particular you can use a generic catch
>> like catch(boost::exception/std::exception) or catch(...).
>
> I do. I hoped I can handle throw foo() in catch( foo ) and
> BOOST_THROW_EXCEPTION( foo() ) in catch( boost::exception ). Former would
> not try to dig inception point info. Later would.
>
> Actually I might want to do it in all clauses after all. I do want to be as
> specific as possible. An alternative is to somehow deduce type at runtime in
> generic catch boost::exception clause, but this seems non reliable.

I might not be understanding exactly what you're doing. In my mind, a
testing framework should assume that (unless you're testing exception
handling) any exception a test emits is unexpected, and then the only
useful thing you can do is log some diagnostic information; I don't
see a need for anything more than

catch(...)
{
  std::cerr << boost::current_exception_diagnostic_information();
}

Here is an example of what this could display:

example_io.cpp(83): Throw in function class boost::shared_ptr<struct
_iobuf> __cdecl my_fopen(const char *,const char *)
Dynamic exception type: class
boost::exception_detail::clone_impl<class fopen_error>
std::exception::what: example_io error
[struct errno_ *] = 2, OS says "No such file or directory"
[struct file_name_ *] = tmp1.txt
[struct function_ *] = fopen
[struct open_mode_ *] = rb

By the way in some IDEs double-clicking the first line in the above
message will open the source location in the editor.

>>> 2. I do not want to print anything. I collect information and return it
>>> (by
>>> throwing another exception) to the higher level, which in turn decides
>>> how
>>> and
>>> where to report it.
>>
>> I don't see the point of throwing another exception
>
> I need to report the error somehow, don't I? Including all the details.

Yes, and in my mind "all the details" are included in the string
returned by boost::current_exception_diagnostic_information. If
anything useful is missing from that string, then it should be
included instead of doing something else.

>> but if that's what
>> you want to do then you could use boost::exception_ptr:
>>
>> catch(...)
>> {
>>  BOOST_THROW_EXCEPTION(another_exception(boost::current_exception()));
>> }
>
> I do not see why I need BOOST_THROW_EXCEPTION. I do not care about this
> exception inception point. I know it ;) Also I throw this exception in all
> cases when an error occurred (for example in case if signal triggered). It
> operates on strings and numbers.

Sure, you can throw any exception without BOOST_THROW_EXCEPTION.
However there's virtually no overhead in using BOOST_THROW_EXCEPTION.
It does not allocate memory, yet allows users to add arbitrary data in
the exception and to get a boost::exception_ptr to it.

>>>> catch( std::exception & e )
>>>> {
>>>>    //do other stuff furst, then:
>>>>    std::cerr << boost::diagnostic_information(e);
>>>> }
>>>> catch( ... )
>>>> {
>>>>    std::cerr << boost::current_exception_diagnostic_information();
>>>> }
>>>
>>> What is the point of trying to dig something here? Wouldn't the
>>> boost::exception based exception will always be caught in 'catch
>>> boost::exception' clause above?
>>
>> If all you do is get diagnostic_information, then just the catch(...)
>> is sufficient.
>
> But If I already have catch( boost::exception ) I should not try to dig this
> info in catch(...) right?

In this particular case, what would you do with a boost::exception
that's different from what you'd do with any other exception in a
catch(...)?

>>> Ok. So how do I do this?
>>
>> Use get_error_info<throw_function>(e), get_error_info<throw_file>(e),
>> get_error_info<throw_line>(e).
>
> What is the requirement on type of e? can it be char*? Or std::string?

e is the exception you catch. Here's how you use it:

if( char const * const * f=get_error_info<throw_file>(e) )
{
    //*f is a char const * that points the file name string.
}
if( char const * const * f=get_error_info<throw_function>(e) )
{
    //*f is a char const * that points the function name.
}
if( int const * l=get_error_info<throw_line>(e) )
{
    //*l is the line number
}

> Can we have something like 'cause', which will be the same as
> diagnostic_info, but without inception point?

For what reason? It seems to me that you're trying to make the
returned string "prettier" which is unrealistic. The string is pretty
much guaranteed to be ugly to look at yet rather informative. :)

That said, I do agree that especially if you're generating some kind
of xml report, processing the location of the throw specifically is a
good idea.

Emil Dotchevski
Reverge Studios, Inc.
http://www.revergestudios.com/reblog/index.php?n=ReCode


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net