Article View: comp.std.c++
Article #2626Re: Exceptions in destructors
From: J. Kanze
Date: Fri, 17 Nov 1995 00:44
Date: Fri, 17 Nov 1995 00:44
104 lines
5441 bytes
5441 bytes
Anatoli Tubman (anatoli@ptc.com) wrote:
|> James Kanze <kanze@lts.sel.alcatel.de> writes:
|> > 1. Given:
|> > T a[ 5 ] ;
|> > When destructing the third element (for example), an exception is
|> > thrown. Are the remaining elements destructed? I would say yes
|>
|> Unfortunately, DWP is not clear enough in this area.
|> Here what it says (the numbers of statements are mine):
|>
|> (1) An object that is partially constructed will have destructors
|> executed only for its fully constructed sub-objects.
|> (2) Should a constructor for an element of an automatic array throw an
|> exception, only the constructed elements of that array will be
|> destroyed.
Does this only apply to automatic arrays. I thought it applied to all
arrays.
|> (3) If the object or array was allocated in a new-expression, the storage
|> occupied by that object is sometimes deleted also.
|> (Note that (3) does not appear in the ARM.)
|> I think that (2) should be rewritten, perhaps like this:
|> (2*) An object becomes fully constructed when its constructor returns
|> and remains such until a destructor for it is invoked.
IMHO, this is already covered in (1).
|> This covers the case covered by the present wording, and many others, for
|> which DWP makes no provisions -- without violating the spirit.
|> Also, (3) needs to be a little bit more specific. I think the following
|> will do well:
|> (3*) A delete-expression always deletes storage allocated for its
|> operand, regardless of any exceptions that might be thrown by any
|> of the destructors involved.
This is an entirely new point (4). (3) talks about exceptions in
new-expressions; here we talk about exceptions in delete-expressions.
Consider the following:
auto_ptr< T >* pp = new auto_ptr< T >[ 3 ] ;
// ..
delete [] pp ;
According to the standard, this will result in calling the destructors
of auto_ptr on pp[ 2 ], pp[ 1 ] and pp[ 0 ], in that order, then calling
operator delete[] on the resulting raw memory. The destructors for the
auto_ptr's will delete the object they point to.
Now suppose that T::~T() throws an exception when destructing pp[ 1 ].
If the implementation does not continue by destructing pp[ 0 ] and
calling operator delete, there is *no* way the user can. Even if the
user traps the exception, he cannot call ``delete [] pp'' a second time,
since this would cause the destructor of the already destructed pp[ 2 ]
to be called. He could not even attempt to do the job by hand, calling
explicitly the remaining destructors, and then operator delete[], for
several reasons:
1. He has, a priori, no way of knowing how many of the objects have
already been destructed.
2. Even if he did, he cannot call the destructor on the auto_ptr element
in which the exception occurred. So the memory that auto_ptr pointed to
is lost.
3. Even solving this problem, he cannot call operator delete[] directly,
since it is not guaranteed that the address returned by operator new[]
is the same as that returned by the new expression (and in general, in
the above case, it isn't).
|> If an implementation does not impose an added cost to code that does not
|> catch or throw exceptions, it can be easily modified to comply with the
|> above rules and still add no overhead to such code.
|> Whether throwing from destructors shoud ever be considered by the C++ user
|> (as opposed to implementor) is a totally different question.
|> I believe that inability to destroy what you've just created
|> is a symptom of some very serious problem, for which terminate() is an
|> appropriate solution. However, standards should not prohibit
|> things only because they are ``bad style'' -- there must be other reasons.
Agreed. In the internet protocol suite, there is a ``robustness
principle'' which states: "Be liberal in what you accept, and
conservative in what you send." I like to apply this generally: a user
should not allow exceptions to escape from destructors, but the
implementaion (and the language definition) should work when the case
occurs. (Note that unless the implementation does go on to free the
memory, auto_ptr is not exception safe under its current definition.)
--
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:
<48f4ak$pro@gabi.gabi-soft.fr>Path:
arc1-ca.pugleaf.net!in2.uu.net!bounce-backReferences:
<Pine.SGI.3.91-heb-2.02.951114164854.2393A-100000@arava>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!in2.uu.net!bounce-back Date: 17 Nov 95 00:44:08 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: 16 Nov 1995 11:38:12 +0100 Organization: GABI Software, Sarl. Message-ID: <48f4ak$pro@gabi.gabi-soft.fr> References: <Pine.SGI.3.91-heb-2.02.951114164854.2393A-100000@arava> X-Newsreader: TIN [version 1.2 PL2] X-Auth: PGPMoose V1.1 PGP comp.std.c++ iQBFAgUBMKvbpOEDnX0m9pzZAQHBEAGAj0N8S3jASGwtjHfNP6j1wqx3zUQCOeeb DYv5UXmQPkpFNdz6OvWVBG8QbVYPkkon =H6FX