Article View: comp.std.c++
Article #2728Re: Exceptions in destructors
From: J. Kanze
Date: Mon, 27 Nov 1995 12:57
Date: Mon, 27 Nov 1995 12:57
124 lines
7007 bytes
7007 bytes
Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
|> kanze@gabi-soft.fr (J. Kanze) writes:
|> >Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
|> >|> schuenem@informatik.tu-muenchen.de (Ulf Schuenemann) writes:
|> >
|> >|> >How about saying that dtors have an empty exception-specification
|> >|> >(either by default or always) ?
|> >
|> >|> How does that help?
|> >
|> >|> >Then there are 3 cases possible:
|> >|> >- The dtor causes no eception.
|> >|> >- The dtor catches all exceptions and continues - save,
|> >|> > but what happens to client-provided exception handling ?
|> >|> >- The dtor does not handle an exception that happend to be
|> >|> > be raised - unexpected() is called.
|> >
|> >|> Yes, and what if the programmer has defined unexpected()
|> >|> to rethrow the exception? (In most circumstances, doing so
|> >|> is probably a much better idea than just crashing via
|> >|> a call to abort().)
|> >
|> >1. How can it know what the exception was to rethrow it? Is a throw
|> >without an argument legal here? (I don't think so, but I'm not sure.)
|> Yes, a `throw;' statement is legal within an unexpected() handler.
|> 15.1/5-6 is quite clear:
|> | 5 A throw-expression with no operand rethrows the exception being han-
|> | dled without copying it.
|> |
|> | 6 The exception thrown is the one most recently caught and not finished.
|> | An exception is considered caught when initialization is complete for
|> | the formal parameter of the corresponding catch clause, or when termi-
|> | nate() or unexpected() is entered due to a throw. An exception is
|> | considered finished when the corresponding catch clause exits.
|> On entering unexpected(), the exception is considered handled, but not
|> finished, so `throw;' is fine.
|> The ARM contains an example of the use of `throw;' in an unexpected
|> handler (pages 365-366).
Great. So what does it mean. Suppose I write a function:
void f() throw() ...
What I'm trying to guarantee is that this function does not throw any
exceptions; this is a very important guarantee if exception safety is to
be taken seriously. In fact, of course, I've only guaranteed that it
won't throw any exceptions other than bad_exception (which is already a
serious compromise).
If unexpected does rethrow (or if it throws any exception other than
bad_exception), then I would expect unexpected to be called. If the
exception specifications are to mean anything, then the exception cannot
propagate out.
(IMHO, at least in the case of throw(), even bad_exception shouldn't
propagate out. Basically, allowing bad_exception to be an exception
means that even functions like the above can throw exceptions, which in
turn makes exception safety significantly harder; you must be prepared
to accept an exception at any time, since there is *no* way to ensure
that a given function never throws an exception.)
|> >2. This behavior doesn't seem conform to the required behavior in
|> >18.6.1.2. I believe that when a user provided routine violates required
|> >behavior, undefined behavior results.
|> Hmm, you're right - according to 18.6.1.2, an unexpected handler
|> must not throw the same exception. This would seem to imply that
|> `throw;' would be ok in an unexpected handler only if the exception didn't
|> escape, e.g.
|> void my_unexpected_handler() { try { throw; } catch(...) {} }
|> and also that the example in the ARM has undefined behaviour.
|> On the other hand, 15.5.2 definitely seems to assume that an
|> unexpected handler can throw an exception not in the exception
|> specification, and carefully describes the behaviour in that case.
|> So the draft is self-contradictory here. I think all you can really
|> say is that one of 15.5.2 and 18.6.1.2 is wrong.
I don't really think that this is a contradiction. 15.5 is speaking
about when the C++ language considers an exception finished (and thus,
*potentially* capable of being rethrown). This is necessary even when
the exception cannot actually be rethrown; it also defines when the
destructor of the exception is called. Thus, for example, the
constructor of an exception could save its this pointer in some global
variable; the `unexpected' function could then access the exception for
additional information. (And yes, I am aware that the current wording
of 15.5.2 doesn't say anything like this. But I think it is implicit in
the fact that a rethrow *must* throw the same object, not construct a
new one. It would be nice if there were some exact wording specifying
when the destructor of the exception will be called, however.)
The statements in 18.6.1.2 specify the semantic constraints of a
particular function. Thus, IMHO, the language per se allows rethrow at
this particular time, but the semantic constraints of the library do
not. (This is sort of like operator new() returning NULL. The
`language' per se certainly allows it, but the semantic constraints
specified in the library section do not. And while I agree that the
library is part of the language, its specification defines an additional
layer or level of constraint, distinct from the rest of the language.
IMHO, of course.)
In this regard, thus, I do not think that there is a contradiction,
although perhaps a footnote in 15.5.2, pointing out that the library
does introduce additional constraints, would be in order. (On the other
hand, if you start adding footnotes everywhere that a different section
may introduce additional constraints, you are likely to end up with more
footnotes than standard proper. I imagine that Andy Koenig and his
helpers have enough to keep them busy anyway.)
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Technical Details
Message-ID:
<49c1hh$o5s@gabi.gabi-soft.fr>Path:
arc1-ca.pugleaf.net!in1.uu.net!bounce-backReferences:
<Pine.SGI.3.91-heb-2.02.951114164854.2393A-100000@arava> <48s8fa$aq@sunsystem5.informatik.tu-muenchen.de> <9532523.1824@mulga.cs.mu.OZ.AU> <494oog$hmf@gabi.gabi-soft.fr> <9533100.19015@mulga.cs.mu.OZ.AU>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!in1.uu.net!bounce-back Date: 27 Nov 95 12:57:36 GMT Approved: fjh@cs.mu.oz.au From: kanze@gabi-soft.fr (J. Kanze) Newsgroups: comp.std.c++ Subject: Re: Exceptions in destructors X-Original-Date: 27 Nov 1995 10:48:33 +0100 Organization: GABI Software, Sarl. Message-ID: <49c1hh$o5s@gabi.gabi-soft.fr> References: <Pine.SGI.3.91-heb-2.02.951114164854.2393A-100000@arava> <48s8fa$aq@sunsystem5.informatik.tu-muenchen.de> <9532523.1824@mulga.cs.mu.OZ.AU> <494oog$hmf@gabi.gabi-soft.fr> <9533100.19015@mulga.cs.mu.OZ.AU> X-Newsreader: TIN [version 1.2 PL2] X-Auth: PGPMoose V1.1 PGP comp.std.c++ iQBFAgUBMLm1zuEDnX0m9pzZAQFDmgF/dQNLmBHySGGUtygZY99/Gr/yOzmxr83N 9S79lTTBtqO4yyElg0s32B/p4LWT85f2 =E645