Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-03-22 10:47:56


>From: "David Abrahams" <dave_at_[hidden]>

> Terje Slettebø <tslettebo_at_[hidden]> writes:
>
> >>From: "David Abrahams" <dave_at_[hidden]>
> >
> >> Terje Slettebø <tslettebo_at_[hidden]> writes:
> >>
> >> >> C:\Program Files\Boost\boost_1_30_0\boost/lexical_cast.hpp(74) :
> > warning
> >> > C4512: 'no_lexical_conversion<class std::basic_string<char,struct
> >> > std::char_traits<char>,class std::allocator<char> >,long>' :
assignment
> >> > operator could not be generated
> >> >
> >> > This is due to that it stores a const std::string object, describing
the
> >> > exception
> >>
> >> Are you saying that you have defined an exception with a std::string
> >> member? That's VERY bad! Throwing that exception can lead directly
> >> to termination!
> >
> > You mean if the exception itself throws during construction or copying?
>
> Yes.
>
> > I've tried the program below on Intel C++ 7.0 and MSVC 6, and I haven't
got
> > it to call terminate(). It may be that it doesn't handle exceptions
> > correctly, though.
>
> Because you are not running in a low-memory condition.

What difference would that make? In the example program, it throws an
exception from the exception constructor, effectively simulating an
out-of-memory exception.

> > As it stands, it prints "Exception - Constructor", as it throws an
exception
> > in the constructor of the Exception exception. If the throw-statement in
the
> > constructor is commented out, it prints "Exception - Exception",
apparently
> > not invoking the copy constructor when throwing the exception (which
it's
> > allowed to).
>
> Irrelevant. A program that invokes undefined behavior may appear to
> work fine also.

You said that it may terminate the program. I assumed from that that you
meant it would call terminate(). Did you instead mean undefined behaviour?
If so, how? And how would that be related to terminating the program? As you
say, anything can happen with undefined behaviour, including the "expected"
behaviour.

> >> What's wrong with char const*?
> >
> > You mean storing the string as a character array?
>
> No, I mean not storing the string at all (char const* is not an
> array), but storing an array is another option.

Yes, I know that, of course. However, since if you just store a pointer, the
string has to be allocated some other way. How would you allocate it? If you
use "new", won't that bring the same potential problem as std::string? This
is why I thought you might have meant storing an array (as STLPort does it),
rather than storing a pointer. Storing an array eliminates the possibility
of throwing an exception at construction.

> > Sure, that's possible, and I see that STLPort do it, and it's
> > probably safer, as you say. It does mean you have to specify the
> > maximum string length in advance, though. As "no_lexical_conversion"
> > what() prints out the source and target types, it may truncate long
> > type names.
>
> There's no guarantee you have readable names anyway. Finally, you
> should never format exception messages at the throw point. An
> exception whose what() needs to print type names should store the
> typeids and put the formatting logic in what().

A problem is that what() can't throw, either. So you'd have to wrap it in a
try-catch. Then there's the issue of what to return from what() if the
formatting throws.

As Kevlin says in another posting, the "terminate on second exception",
which I thought you alluded to in your first reply, and maybe you did, may
not apply at the point of construction, since it only applies after the
evaluation of the throw-expression. In other words, if the construction
fails, you only loose the first exception, and it instead throws the new
one.

As for throwing in the copy constructor, that might be a problem, since the
"call by value" semantics of throwing an exception may mean that it makes a
copy of the exception, after the throw-expression is evaluated.

The reason the extended error type was added, was that there has been
requests on this list for storing the types used in the conversion, in the
exception, to make it easier to know which conversion failed. It has also
proved useful in the regression testing. bad_lexical_cast was not modified,
to not break the interface, so this type inherits from it.

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk