From 5556461461275582056
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,96a8c01f7043c2d9
X-Google-Attributes: gidf78e5,public
X-Google-ArrivalTime: 2002-09-26 10:33:55 PST
Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!canoe.uoregon.edu!logbridge.uoregon.edu!kibo.news.demon.net!mutlu.news.demon.net!demon!mail2news.demon.co.uk!devnull
From: belvis@pacbell.net (Bob Bell)
Newsgroups: comp.std.c++
Subject: Re: Proposal: exception stack unwinding resumption
Date: Thu, 26 Sep 2002 17:33:54 +0000 (UTC)
Organization: http://groups.google.com/
Lines: 233
Approved: fjh@cs.mu.oz.au (Fergus Henderson , moderator of comp.std.c++)
Message-ID: <c87c1cfb.0209251540.4025e42@posting.google.com>
References: <6df0c6a8.0208260746.633710cb@posting.google.com> <23b84d65.0209161107.23bea618@posting.google.com> <6df0c6a8.0209170602.2cb54634@posting.google.com> <RW_h9.899$nU2.53545@newsfep1-gui.server.ntli.net> <6df0c6a8.0209201925.6faa9e57@posting.google.com> <c87c1cfb.0209220939.46d823af@posting.google.com> <6df0c6a8.0209230602.2aba3ca8@posting.google.com> <c87c1cfb.0209231924.6b639ab2@posting.google.com> <6df0c6a8.0209240716.6fb5ec00@posting.google.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
X-Trace: mail2news.demon.co.uk 1033061634 27717 10.0.0.1 (26 Sep 2002 17:33:54 GMT)
X-Complaints-To: abuse@demon.net
NNTP-Posting-Date: Thu, 26 Sep 2002 17:33:54 +0000 (UTC)
X-Received: from mulga.cs.mu.oz.au ([128.250.1.22])
	by news.demon.co.uk with esmtp (Exim 4.05)
	id 17ucWO-0007Cu-00
	for mail2news@news.news.demon.net; Thu, 26 Sep 2002 17:33:53 +0000
X-Received: from localhost (localhost [[UNIX: localhost]]) by mulga.cs.mu.OZ.AU
	id DAA12480; Fri, 27 Sep 2002 03:33:17 +1000 (EST)
X-Authentication-Warning: mulga.cs.mu.OZ.AU: fjh set sender to devnull@stump.algebra.com using -f
X-Path: comp-std-cpp-robomod!not-for-mail
X-Robomod: STUMP, ichudov@algebra.com (Igor Chudov)
X-Delivered-To: std-c++@ncar.ucar.edu
X-Newsgroups: comp.std.c++
X-NNTP-Posting-Date: 25 Sep 2002 23:40:26 GMT
Xref: archiver1.google.com comp.std.c++:14226

pierrebai@hotmail.com (Pierre Baillargeon) wrote in message news:<6df0c6a8.0209240716.6fb5ec00@posting.google.com>...
> belvis@pacbell.net (Bob Bell) wrote in message news:<c87c1cfb.0209231924.6b639ab2@posting.google.com>...
> > pierrebai@hotmail.com (Pierre Baillargeon) wrote in message news:<6df0c6a8.0209230602.2aba3ca8@posting.google.com>...
> > > belvis@pacbell.net (Bob Bell) wrote in message news:<c87c1cfb.0209220939.46d823af@posting.google.com>...
> > > > pierrebai@hotmail.com (Pierre Baillargeon) wrote in message news:<6df0c6a8.0209201925.6faa9e57@posting.google.com>...
> > > 
> > 
> > I disagree here. Current best practice seems to do pretty well
> > already. My point is that you haven't yet established (to my
> > satisfaction anyway) that current best practice is insufficient.
> 
> The current best practice (CBP) is sufficient for the current
> situation where the language makes it difficult to determine if it is
> safe to throw from the destructor. But anyway, I am very interested
> about what would be a convincing argument for you and the other
> detractors.

Your proposal doesn't make it safe to throw from a destructor. It just
prevents the program from calling std::terminate, which is somewhat
different. I guess that's the capsule summary of what's wrong with
this proposal.

> I agree that the main weakness of the proposal is the switchable
> behavior. I only proposed the switchable behavior to make the proposal
> more acceptable to people who like the current terminate() calls.
> 
> I'm starting to believe that I was wrong on that point. Most
> detractors mentionned that point. What's more, I've just read Francis
> Glassborow's post in which he mention that he would like:
> 
>    "> destructors never throw.
>       [snipped]
>     And I wish we could actually make that the default for dtors"
> 
> Which I take it to mean that they would have an automatic invisible
> try/catch block. My proposal only difference is to allow the exception
> to escape the destructors when it could.

I can't speak for Francis, but I would interpret his remark as
"destructors should behave as if they were declared with a throw()
exception specification." In other words, any exception escaping a
destructor would lead to a call to std::unexpected. That's the
behavior I would like.

> > How do I test that a destructor will never throw? One simple way,
> > mentioned by you, is to wrap every destructor in try/catch. Another
> > way, mentioned by Francis in his reply, is don't call functions that
> > can throw. Usually, an inspection or review of the destructor code is
> > all that is needed to verify that the destructor does not call
> > throwing functions. This is viable because most destructors (that I
> > write anyway) are trivial compared to the rest of the program, and
> > usually do little more than release resources.
> 
> It's all true, but a bit of a simplification, IMO. In code reviews,
> nothing in the call signature of a function tells you that it will
> throw or not. It's always a matter of memory and consistent
> maintenance to know that. Of course if you don't want your destructors
> to throw you will keep them doing the least possible work. I know that
> convincing people that expanding their usefulness is a hard battle.

Destructors really shouldn't do much work. They definately shouldn't
do things that can fail.

> > I agree with him that classes that can throw from destructors are
> > broken. Consider a class A with a base class B. A::~A runs and throws.
> > Not only is A::~A interrupted (which may cause it to leak resources,
> > etc.), but the B::~B never gets called!
> >
> > Note that your proposal doesn't make this situation better.
> 
> I'd like to be corrected if I'm wrong, but I'm quite certain that if
> ~A() throws, all its data members and base classes are destructed. The
> relevant clause, I believe, is 15.2, where it is said that partially
> constructed objects will have their fully constructed parts destroyed
> properly. It even mention that it works for arrays.

I don't have a copy of the standard, but I'll give you my
understanding of the language. Perhaps someone else who does have the
standard can settle this for us.

"Partially constructed objects" refers to exceptions that are thrown
by a constructor, not a destructor. The intent is for the language to
guarantee that objects the programmer cannot access are destroyed
(since the object has not yet finished constructing, the programmer
has not been able to obtain a reference to it).

If an exception is thrown from some function that is _not_ a
constructor, then only stack objects are destroyed. Therefore, if
A::~A above throws, since the B part is not a stack object, B::~B will
not be called.

I'd be interested in anybody else's opinion on this as well. I just
ran a quick test in CodeWarrior 7, and it seems to agree with my
interpretation.

> > But I think that ignoring the new exception is just as bad, but for
> > slightly different reasons. You still suffer from information loss
> 
> No worse that with a try block in destructors, which is what is done
> now.

No, actually it is worse, because a try block in a destructor will not
prevent members and bases from being destroyed.

> > and
> > resource leakage, but because the exception evaporates, there is
> > nothing that any part of the program can do about it. Imagine a
> > std::vector<Foo> being destroyed, where the destructor of the first
> > Foo throws, leaving every other Foo, and possibly the std::vector,
> > constructed and allocated, but leaked. And because the program doesn't
> > terminate, it still limps along in some unpredictable, inconsistent
> > state.
> 
> Objects which throw in their destructors cannot be used in STL
> containers per the STL specification. My proposal doesn't change this,
> which means that objects that throw cannot be used with STL
> containers.
> 
> I didn't want to include changes to the STL in my proposal to limit
> its scope. It would also be beyond my ability to correctly specify all
> needed changes.
> 
> > > Tell me, what do you do in your destructors to have them not throw?
> > > You put a try/catch. You catch everything, including divisions by zero
> > > and invalid memory accesses on some implementation (MSVC++). You loose
> > > information. That is the current best practice.
> > 
> > You're ignoring the possibility of designing the class to not call
> > throwing operations in the destructor, which is the preferred method.
> 
> OK, then I'll admit that it is the preferred method. But there is a
> nagging detail: what I would put in the destructor, the footer(), you
> have to put somewhere else, right? That somewhere else, in the face of
> an exception, must catch all exceptions, right?

Why? This doesn't follow at all. Presumably you're referring to code
like:

   header();
   body();
   footer();

Why is there a special need to catch exceptions thrown by footer?

> So what is different
> here? Only the location of the code, not the behavior. Let's take a
> real life example:
> 
> You have a resource, shared by many objects, that is ref-counted. Each
> object grabs it when it needs it and releases afterward. When the
> resources is released it may have to do some work on behalf of the
> other objects. The real resource here is a color table that must be
> written to a file. Accesses to the color table and file obviously have
> to be serialized this way. The concurrent accesses may be actually
> spread over many threads (so it is not simply a matter of reorganizing
> code).
> 
> My code:
> 
> {
>    Ref<Resource> ref( ColorTableManager.getCompressor() );
>    //... use color table, may throw.
> } // release happens here, exception may be swallowed.
> 
> 
> Your code (correct me if I'm wrong):
> 
> {
>    Ref<Resource> ref( ColorTableManager.getCompressor() );
>    //... use color table.
>    ref.release(); // sets a flag to not do work in destructor.
> } // does release() in try block in destructor if flag not set.
> 
> I'm very interested to see how you and other detractors would write
> that code. The point of the code example is: you have to release
> something that can fail. *Where* you do it is only a red herring, you
> have to do it anyway. The benefit of my code and proposal is that
> there is more automation (and one less flag).

Actually, here's my version:

{
   Ref<Resource> ref(ColorTableManager.getCompressor() );
   //... use color table, may throw.

   ref.WriteToFile(); // may throw.

} // destructor releases using non-throwing operations only.

I would separate the behavior so that destruction doesn't write to a
file or perform any throwing operations. Throwing operations would be
placed into a new function, which a client would be required to call
as above.

> > > My proposal just makes it automatic, language-enforced. You gain
> > > flexibility in the bargain because in the normal case (i.e.: not stack
> > > unwinding), your destructors will *not loose information*. So acording
> > > to you, my proposal is a gain. right? ;-)
> > 
> > Not only is the exception lost, but the object that generated it goes
> > to The Twilight Zone, because it's neither alive nor dead. All legal
> > references to the object are gone, so nothing meaningful can be done
> > to correct the situation. That sounds like information loss to me.
> 
> See above code example the discussion about 15.2 above. Prove me
> wrong.

I can't prove it, but you're wrong. ;-)

> > You're giving the programmer a function,
> > set_unwinding__resumption, and allowing him to call it at any time.
> > You can't hand-wave it away by saying that probably he'll call it once
> > at the beginning.
> 
> I agree, it's the weak point of my proposal. Would it be more
> acceptable if the proposed behavior would always be enabled? That
> would not change the meaning of existing code, since it has really
> been properly tested and reviewed right? ;-). Seriously folks, would
> the proposal be more acceptable like that? I didn't say acceptable
> (yet), just more...

Actually, it would be a step in the right direction. But getting back
to the capsule summary line at the beginning of this post, it still
would not make exceptions from destructors safe.

Bob

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]



