🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

2 total messages Started by Herb Sutter Wed, 22 Nov 1995 04:46
Exceptions and dtors
#2692
Author: Herb Sutter
Date: Wed, 22 Nov 1995 04:46
101 lines
6054 bytes
PROBLEM: Basic Inconsistency (Ctors and Dtors and Exceptions)

It's occurred to me that the basic inconsistency in current exception
rules still hasn't been resolved:

- On one hand, exceptions are (among other things) meant to be a way to
provide error handling mechanisms for ctors, since ctors cannot return error
values.  This is not only legitimate, but elegant and necessary.

- On the other hand, under current rules we dare not use exceptions to provide
error handling mechnisms for dtors, even though these share the same problem
with ctors (both cannot return error values).  Briefly, this is because the
dtor might be called during stack unwinding while another exception is already
active, and under the current rules any further exceptions thrown in that
state abort the program.

I'm not convinced that last 'must abort' rule is necessary.  It seems clear to
me that the ctor and dtor needs are quite similar and that excluding one from
using exceptions as error returns (not by language rule, but by making it so
dangerous as to be shunned) is most unfortunate... particularly since the
dangerous case is rare and the vast majority of the time dtor exceptions would
be fine even now.


PROPOSAL: Allow Multiple Simultaneous Exceptions

Consider a change in the rule for exceptions thrown during stack unwinding
(note: this proposal doesn't affect any other part of the standard, it doesn't
impose burden on code not making use of it, etc.).  Suppose that an exception
is active and the stack is being unwound, and while one dtor is being
processed it throws its own exception... instead of arbitrarily halting the
program, we simply add the new exception to the existing list of active
exceptions; the dtor throwing the new exception is naturally exited (just as a
ctor that throws is exited), but destruction continues as usual... the program
first calls dtors for member objects, then the base dtors, etc.  Informally,
the program continues stack unwinding as before, except that now two
exceptions are known to be active and the dtor that threw the second exception
naturally didn't complete because it threw.

Basically all that's now needed is a rule for when to stop.  There seem to be
two main possibilities.  In both, we keep unwinding (and possibly adding new
exceptions as we go) until a handler for any one of the active exceptions is
found (if there are two exceptions of the same type, use some rule, e.g.
"first thrown first handled", to define which gets handled first).  Then,
either:

a) discard all other active exceptions and continue execution from the handler
for the first matched exception (this may allow other errors to be left
unhandled, but there may be valid arguments in favour of this, e.g. 'but
that's the first handler that claimed it could do something about this tragedy
with possibly multiple symptoms [exceptions], and since the exceptions are
likely related this handler is probably the one we should want since it does
in fact know how to handle a symptom'); or

b) invoke the matching handler, remove the handled exception from the list,
then continue unwinding (adding any new exceptions if they're thrown and
invoking handlers to get rid of active exceptions as valid handlers are
encountered) until we've handled the last active exception, then continue
progam control flow from after that handler (I like this better in some ways
and there may be arguments for this as well, e.g. 'this way all our individual
errors/symptoms get specifically addressed', but (a) also has its share of
elegance and arguments).


ADVANTAGES:

This scheme allows exceptions to be properly and safely used in dtors.  By far
the majority of the time dtors aren't being called in the context of an
exception anyway, and so the current rules impose undue hardship by making
dtor exceptions so unsafe as to be unusable (because even one at a bad time
could crash the program), when in fact even now dtor exceptions are already
safe the vast majority of the time.  The rules just make the 'rare' case so
incredibly dangerous that it can't be risked and must be avoided completely.
In so doing, the current rules create an inelegant -- and, worse, inconsistent
-- partial solution that addresses half the problem (errors in ctors, for
ctors can't return values) while leaving the identical other half unaddressed
(errors in dtors, for they have the same restrictions as ctors and the problem
is basically no different).


SUMMARY:

It seems clear to me that the main question with the above is probably: 'When
do we stop unwinding?'  That is, do we stop as soon as we can handle any of
the active exceptions? when we've handled all of them? or something else?
Personally, I think that either of the first two answers would probably be
fine and so complicated rules should be unnecessary, but only further
discussion can prove or disprove that 'I think that...'. :-)

Comments and discussion welcome.

Herb


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter                 2228 Urwin, Ste 102         voice (416) 618-0184
Connected Object Solutions  Oakville ON Canada L6L 2T2    fax (905) 847-6019
---
[ 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. ]
Re: Exceptions and dtors
#2773
Author: Dick Menninger
Date: Tue, 28 Nov 1995 00:55
130 lines
6469 bytes
> ==========Herb Sutter, 11/21/95==========
 
> PROBLEM: Basic Inconsistency (Ctors and Dtors and Exceptions)
 
[discussion focused on ctors and dtors deleted]

Actually, the inconsistency seems more basic, though
what was said seems true.  Any code, including code
called in ctors, dtors, and exception handlers or implied
execution in the companion unwinding that must occur
should be capable of being common use code that can
want to throw exceptions independent of any other
exception already thrown.  From an application design
viewpoint, THIS IS NOT A RACE with the first exception
thrown winning and the rest swallowing their "pride"
and going quietly away.  There may be differences in
the importance of the exceptional conditions that are
found, but there is never any plausible reason that
could be given that the more important one will be
found first or that NOT being able to throw one makes
sense (it seldom does in any high availability/reliability
system design).  Even if two exceptional conditions
are of equal importance or the more important gets
thrown first, it does not seem to be very plausible
that swallowing only the first makes much sense.

Exceptions provide a control paradigm in for readily
backing out of portions of call stacks that allows
some disciplined use of call frames for data.  But
the current scheme seriously limits it useability.
Certainly we do not want to go back to the "globals
and heap only" approach necessitated by a
setjump/longjump approach.  But the current scheme
is almost as distorting of design by forcing a one
at a time design and not giving any good means
of insuring that any libraries used will gracefully
fit into that.  Yet it forces them to be used.
The door has been opened, but now you have to
go all the way through.

> PROPOSAL: Allow Multiple Simultaneous Exceptions

[ An inadequate proposal is deleted ]

I like the sentiment, but the details don't make
the grade.  First the possible multiple exceptional
condition cases need to be more accurately delineated.
Then the handler cases need to be matched up with them.
First, there may be unrelated exceptional conditions that
occur in the same window (window meaning
additional conditions need to be detected and raised
before some other condition has been handled).
Second, there may be similar but distinct exceptional
conditions that occur in the same window.  Third,
there may be separate detections of a common
exceptional condition.  Each of these may have its
own needs.

In the third case, it may be much easier to write
software if you could say something to the effect of
"throw this if it is not already thrown."  Obviously,
determining the identity for "already thrown" is the
key issue.  But here the needs are on the throw side.

In the second case, the exceptions need to be
distinguishable at throw time yet are likely to need
handling by the same handler or sequence of handlers
as you unfold.  Here, the handler may successfully
handle one subset and need the throw a remaining
subset.  Some may even fit part of the first case as
discussed below.

In the first case, you have two kinds of handler
situations: single handlers that handle unrelated
exceptional conditions and cascades of handlers
that handle various subsets of them, both of these
having the potential of successfully handling subsets
and rethrowing other subsets.  The order of looking
at the exceptional conditions may matter.  [cascade
is used in the sense of multiple catches for a try.]

These are the static cases.  That is, these are the
cases where the appilcation exception handling
is fixed at compile time.  I bring this up as a distinction
as I also see a possible need for runtime exception
handling binding.  However, compared to the static
case this is a frill where a good solution for the static
case is a necessity.

A library may want to establish base level handling
of its exceptions at the outer call layer to insure that
basic handling will happen if the calling application
does none.  This would force the unwinding of the
call frames, which may be important to the library's
provided service, and would then allow the basic
exception code specified by the library to be called
at the tail end.  This is dynamic in the sense that
the library may need to establish this when called,
particularly if the linkage to it is created at runtime
with use then distributed.  If the application does
"handle" the exceptional condition, the library can
get notified via the destructor call for the exception
instance and it may need to rethrow if it was not
really handled.

So, I tried here to outline the real problem as I see it.
I feel that much of the squirming going on now with
respect to exceptions is because the current mechanism
in woefully inadequate in fundamental ways.  The rest,
of course, is due to partial shock at the implications
of really dealing with exceptional conditions and partial
denial in most people's design and code.  An amazing
amount of code never checks for errors since that
would "distort" the design too much.  Taking a major
part of that distortion away is what the exception
control paradigm should do (making this excuse
as lame as feasible), but it has to solve the full problem
to be truly useable.



Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM


[ 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. ]
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads