Dave said:
...
Wow, your second points brings up something really interesting! What you
are saying makes perfect sense. Yet when I look at the Standard, I see
standard exceptions that don't explicitly state that their destructor has an
exception specification of throw (). For example, consider 19.1.1. Is this
a problem with the Standard?????
No, there's no problem here. Firstly, take a look at 18.6.1. The
declaration of the destructor of 'std::exception' _does_ explicitly
include an exception specification. And it is 'throw()', exactly as I
said above.
As for the other standard exception classes (such as 'std::logic_error'
in 19.1.1), I still don't see any problem here. They all inherit from
'std::exception' and nowhere in the standard it says that their
destructors have exception specification different from the one that
'std::exception::~exception()' has - that would be simply illegal
because that would violate 15.4/3.
Note also, that when user defined class declares no destructor, the
implicitly declared one will have exception specification derived in
accordance with the rules described in 15.4/13. It's the combination of
15.4/13 and 15.4/3 is what makes your code ill-formed. But I never said
it is hopeless. You _can_ have a data member of 'std::string' type
inside your 'std::exception'-derived class, but first you have to take
one or more steps in order to make your code well-formed and relatively
safe.
Firstly, you have to provide an explicit declaration of your class'
destructor with explicit exception specification. For example
class cyclic_t : public std::exception
{
...
~cyclic_t() throw()
{}
...
}
Now the code is well-formed already and should compile. However, if
during the destruction of a 'cyclic_t' object the destructor of
'what_str' subobject suddenly thrown an exception, the control will go
into 'std::unexpected' and you know what happens next. If such behavior
is unacceptable in your case, you have to take another step - provide a
function-level try-block for 'cyclic_t's destructor which will intercept
such exceptions.
That's probably what standard exception classes would do if they wanted
to contain an 'std::string' object as an immediate subobject.
Along the same lines, I see that the standard exception classes also use
std::string to specify what what will return(). These standard exception
classes also seem to be throwing caution to the wind with regard to your
first point too!
I don't see any evidence of that either. These classes accept
'std::string's as their constuctor's parameters. That doesn't
necessarily mean that they _store_ 'std::string's as subobjects. And
even if they do, there's still a way to do it relatively safely, as I
explained above. Moreover, using 'std::string' as a member subobject
could be perfectly reasonable in such exception classes as
'std::logic_error', 'std::range_error' etc. But I would be extremely
surprised if 'std::bad_alloc' contained a data member of 'std::string' type.
I hope we can get a good thread started on this. I'd love to hear what
people have to say and get this hammered out...
I think you can find quite a lot of information on this topic if you
google for it of just read the relevant articles on GotW site.