Topic: Destruction Order


Author: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/01/10
Raw View

Gerhard Menzl wrote in message <3879CAC1.AB37F7A@sea.ericsson.se>...

>The question is: where is the defect, and should a defect report be
>submitted?

I've been told that a defect report will be in rev 9 of the core issues
list, which should be published in a few days.




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gerhard Menzl <gerhard.menzl@sea.ericsson.se>
Date: 2000/01/11
Raw View
kanze@gabi-soft.de wrote:

> |>  >The question is whether the destructors of the base and member
> |>  >classes are to be invoked before the block scope of the derived
> |>  >class  is left. As I say, I would expect this to be the case, and my
> |>  >interpretation of the standard confirms this.  (To tell the truth,
> |>  >before your posting, itnever occured to me that it could be
> |>  >otherwise
>
> |>  While I assumed otherwise.  Entry to the block scope of a ctor only
> |>  occurs after direct base class and member subobjects have been fully
> |>  ctored.  I intuitively expect the destruction process to work in
> |>  reverse.
>
> Can you show me where in the standard it says that entry to the block
> scope of a constructor only occurs after the direct base class and
> member sub-objects have been fully constructed.  In C, at least,
> function arguments are considered to be in scope "as if" they were
> declared at the start of the function body.  (I can find no
> specification in the C++ standard as to the scope of function arguments,
> but I probably just don't know where to look.)  Since I can use function
> arguments in the initialization clauses of the sub-objects, I conclude
> that the constructors must be called at the start of the body.
>
> But the whole thing is emminently unclear.  Given the traditional
> practice, and the fact that there was no vote negating traditional
> practice, it seems certain that the *intent* was that local objects in a
> destructor only be called after the destructors of the sub-objects have
> been called.

I am sorry for re-butting in that late in the discussion, but I've been on
vacation from Usenet and everything. My hopes were that the issue would be
settled before Christmas because I wouldn't have expected it to be that
controversial.

As Francis and John have pointed out, it is really a question of symmetry
and intuitiveness. Consider:

   struct M
   {
      void f () {}
      void g () {}
   };

   struct G
   {
      G (M& rm) : myrm (rm) { myrm.f (); }
      ~G () { myrm.g (); }
      M& myrm;
   };

Now I think you would agree that every compiler should make the following
work as expected:

   struct C
   {
      C ();
      ~C ();
      M mym;
   };

   C::C () { G g (mym); }

i.e. we can rely on mym already having been constructed when the reference
to it is passed to the constructor of the automatic G object. From the -
perhaps overly vague - symmetry rule, it should follow that

   C::~C () { G g (mym); }

works accordingly, i.e. we can rely on mym still existing when G::~G()
accessing it via its reference, myrm. If this were not the case, I would
consider the construction/destruction symmetry and hence the language
broken.

Regarding your reservations about code that relies on
construction/destruction order: I think that it would be a very sad state
of affairs if programmers could *not* rely on it. Consider that the intent
behind constructors and destructors is to automate all the manual, C-style
initialization and deinitialization calls that are so easy to forget or get
wrong. The quintessence of this intent is captured in the "resource
acquisition is initialization" idiom.

Much of the hostility from experienced procedural programmers towards C++
stems from the fact that - to them - it is not obvious what, when, and in
which order things are going on. The standard answer to alleviate these
fears is that this is, in fact, well-defined and, once you get used to C++,
also obvious. If it should turn out that things are not as well-defined and
standardized, that line of defence would crumble. Therefore I think it is
in the interest of all C++ users to disambiguate this issue.

In order to make it clear that this is not a contrived problem I would like
to describe the real context in which it has surfaced. The example I gave
is nothing less than a deliberately obscured and stripped-down
implementation of the Scoped Locking pattern as described by Douglas C.
Schmidt in C++ Report September 1999. The idea is that acquiring and
releasing of synchronization objects is wrapped in a Guard class so as to
automate synchronization management and provide exception-safety for
multithreaded code. Now when you replace M by Mutex and G by Guard, f() by
lock() and g() by unlock(), it becomes immediately obvious why it can be
important for destructors of automatic objects in destructors of outer
objects to access members of the outer object:

   C::~C ()
   {
      Guard guard (myMutex);
      // destruction proper
   }

If the mutex, which is a member of C, is destroyed before the guard, a
crash will ensue. Of course, this can be circumvented by

   C::~C ()
   {
      {
         Guard guard (myMutex);
         // destruction proper
      }
   }

but this is so ugly, counterintuitive, and easy to forget that it indicates
a clear defect in the language or the compiler.

The question is: where is the defect, and should a defect report be
submitted?

Gerhard Menzl

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 2000/01/11
Raw View
Gerhard Menzl <gerhard.menzl@sea.ericsson.se> writes:

|>  Regarding your reservations about code that relies on
|>  construction/destruction order: I think that it would be a very sad
|>  state of affairs if programmers could *not* rely on it. Consider
|>  that the intent behind constructors and destructors is to automate
|>  all the manual, C-style initialization and deinitialization calls
|>  that are so easy to forget or get wrong. The quintessence of this
|>  intent is captured in the "resource acquisition is initialization"
|>  idiom.

The problem is maintainability, and it is a hard call.  On one hand, it
*is* an advantage to make as much as possible happen automatically, so
that programmers won't forget it.  On the other hand, however, code
depending on obscure rules (whether concerning ordering or not) is
difficult to read, and tends to be fragile -- the maintainance
programmer is likely *not* to recognize the dependancy on the ordering,
and thus accidentally break it.

With regards to ordering of constructors and destructors, about all I
would count on is the order of sub-objects within the object, or of
objects in exactly the same scope, where the order corresponds to the
textual order.  And even then -- I try and design classes using virtual
bases so that the order of initialization between the virtual bases will
be unimportant, since small changes in the hierarchy may cause it to
change.

|>  Much of the hostility from experienced procedural programmers
|>  towards C++ stems from the fact that - to them - it is not obvious
|>  what, when, and in which order things are going on. The standard
|>  answer to alleviate these fears is that this is, in fact,
|>  well-defined and, once you get used to C++, also obvious. If it
|>  should turn out that things are not as well-defined and
|>  standardized, that line of defence would crumble. Therefore I think
|>  it is in the interest of all C++ users to disambiguate this issue.

The only complaints about C++ that I've heard from procedural
programmers concern its complexity.  Of course, the order of all that is
taking place implicity *is* part of that complexity.  (I think Plauger
once qualified it as: "Guess what the compiler is doing now," or
something like that.)

I agree that the order should be well defined, so that even programs
with unintentional dependancies either work or don't work, regardless of
the platform.  But counting on hidden ordering will only make your
programs more obscure to the procedural programmers, and re-inforce
their prejudices.

|>  In order to make it clear that this is not a contrived problem I
|>  would like to describe the real context in which it has
|>  surfaced. The example I gave is nothing less than a deliberately
|>  obscured and stripped-down implementation of the Scoped Locking
|>  pattern as described by Douglas C.  Schmidt in C++ Report September
|>  1999. The idea is that acquiring and releasing of synchronization
|>  objects is wrapped in a Guard class so as to automate
|>  synchronization management and provide exception-safety for
|>  multithreaded code. Now when you replace M by Mutex and G by Guard,
|>  f() by lock() and g() by unlock(), it becomes immediately obvious
|>  why it can be important for destructors of automatic objects in
|>  destructors of outer objects to access members of the outer object:

|>     C::~C ()
|>     {
|>        Guard guard (myMutex);
|>        // destruction proper
|>     }

|>  If the mutex, which is a member of C, is destroyed before the guard, a
|>  crash will ensue.

I realized after posting what your example was trying to do.  (I believe
you mentioned mutex somewhere in the posting.)  And I still think that
it is something I would avoid.  Basically, if you need a mutex in a
destructor, I'm already suspicious.  There shouldn't be a problem with
variables with static lifetime (although the standard says nothing about
threads, and thus doesn't guarantee that all destructors of static
objects will be called from the same thread).  An auto variable can only
be accessed from another thread if its address is somehow "published" --
unpublish it before the variable goes out of scope, and there is no
problem.  With dynamic objects, basically, you follow the same strategy
as for auto variables -- you zap all pointers to them *before* starting
destruction.  (This is an ideal case for a function with delete this.)
Alternatively, in many cases, you can simply delegate all destruction to
a single thread.

|>  Of course, this can be circumvented by

|>     C::~C ()
|>     {
|>        {
|>           Guard guard (myMutex);
|>           // destruction proper
|>        }
|>     }

If the standard worked the way you wanted, then there is a window of
opportunity where the object will appear to be an instance of the base
class.  Definitely not a good idea.

The best solution, if the class is only instantiated on the heap (the
usual case when inheritance is involved) is to declare the destructors
protected, and use a selfDestruct function, which does the necessary
clean-up (including perhaps calls to virtual functions), then invokes
delete this.

|>  but this is so ugly, counterintuitive, and easy to forget that it
|>  indicates a clear defect in the language or the compiler.

|>  The question is: where is the defect, and should a defect report be
|>  submitted?

Given the disagreement, a defect report would definitly seem in order.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 2000/01/02
Raw View
jpotter@falcon.lhup.edu (John Potter) writes:

|>  : Before making such statements, it is necessary to define what the body
|>  : of a function consists of.  Why do you not say, for example, that the
|>  : compiler generates calls to the constructors of the sub-objects at the
|>  : start of the body of the constructor, the same as it generates calls to
|>  : the destructors of the sub-objects at the end of the body.

|>  Because it just does not fit in with everything else.  Things are
|>  normally destroyed in the reverse order of construction.

In certain contexts.  Or rather, within certain subsets of objects.
Thus, this is true of all static objects, and of all local objects, but
there is no relationship in the order of destruction between the two
sets.  (I believe I posted an example of precisely such a case.)
Similarly, the order of destruction of sub-objects is the inverse of
construction, but this guarantee is independant of any construction or
destruction of local or static objects.  (And of course, there are
absolutly no guarantees of order of destruction for dynamic objects.)

IMHO, this is as it should be.  Although the standard quietly ignores
the issue, in most environments, threading is also an issue, and
threading, of course, can wreck havoc with all orderings *except* in
carefully controlled subsets.  A careful programmer just won't count any
anything more than the most limited guarantees.

This is, of course, orthogonal to the immediate question.  The standard
*should* specify clearly whether the destructors of local variables in
a destructor are called before or after the destructors of the
sub-objects -- both destructor calls occur within the same scope.
Personally, I have no great feelings one way or another, but I do think
it preferrable that all compilers behave the same way, whatever that way
is.  (Actually, having no preference is a strong argument for existing
practice.  Which was, at least, sub-objects first.)

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/01/02
Raw View
In article <86ogb57gls.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
>Before making such statements, it is necessary to define what the body
>of a function consists of.  Why do you not say, for example, that the
>compiler generates calls to the constructors of the sub-objects at the
>start of the body of the constructor, the same as it generates calls to
>the destructors of the sub-objects at the end of the body.

We are really playing with words.  However I justify my view of ctors by
considering the way we write them.  ctor-init lists are written outside
the body.  That might just be lexical convenience, but it can also
suggest a viewpoint.  We also distinguish between initialisation of
members and assignment to them.  My view is that all the prior
preparation is done and then the body of the ctor is entered.  That is
not very different from the way functions are called, the arguments are
evaluated and bound to the formal parameters, then we have the sequence
point before entry to the body of the function.

Now when it comes to dtors, I really care very little for the exact
terminology except that it must mean the exact reverse of construction.
I.e. IMO the body of the dtor must clean itself up before arranging for
the subobject dtors to be called.  I believe that is the intent of the
wording.  It is certainly how I have always understood it.  IOWs the
body of a direct base class dtor is not nested at the end of the derived
class dtor but is entered in a way not dissimilar to the way exit is
entered at the end of main.  Note that the behviour of your program is
different if you call exit explicitly as opposed to its call implicitly.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/01/05
Raw View
In article <86k8lt7g9x.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
>But the whole thing is emminently unclear.  Given the traditional
>practice, and the fact that there was no vote negating traditional
>practice, it seems certain that the *intent* was that local objects in a
>destructor only be called after the destructors of the sub-objects have
>been called.

I think it is now clear that we need, at the very least, formal
clarification by J16 & WG21.  Perhaps that should go as far as a defect
report.

BTW despite the reference to C and the scope of a functions forma
parameters, they in fact do not behave in a way that can be written on
entry to the body of a function (there is no defined order of
initialisation, and there is a single sequence point separating them
from the execution of the function.  In a way, the classic form of a C
function definition better describes what happens.  I think what you
were referring to was only intended to clarify the scope of the names of
the formal parameters in a definition (as opposed to the scope in a
prototype)




Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@gabi-soft.de
Date: 2000/01/05
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:

|>  In article <86ogb57gls.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
|>  >Before making such statements, it is necessary to define what the body
|>  >of a function consists of.  Why do you not say, for example, that the
|>  >compiler generates calls to the constructors of the sub-objects at the
|>  >start of the body of the constructor, the same as it generates calls to
|>  >the destructors of the sub-objects at the end of the body.

|>  We are really playing with words.

I know.

|>  However I justify my view of ctors by
|>  considering the way we write them.  ctor-init lists are written outside
|>  the body.  That might just be lexical convenience, but it can also
|>  suggest a viewpoint.

A valid point of view.  However, C originally defined parameters outside
the body, but declared that their scope was in the body, so there is a
definite precedent.

|>  We also distinguish between initialisation of
|>  members and assignment to them.  My view is that all the prior
|>  preparation is done and then the body of the ctor is entered.  That is
|>  not very different from the way functions are called, the arguments are
|>  evaluated and bound to the formal parameters, then we have the sequence
|>  point before entry to the body of the function.

The analogy isn't very strong.  In the case of parameters, the binding
takes place at the call site, not in the function (whereas the
destruction takes place in the body of the function).  Quite different
from the construction of sub-objects.

|>  Now when it comes to dtors, I really care very little for the exact
|>  terminology except that it must mean the exact reverse of construction.

What does the exact reverse mean: that all local variables are
implicitly declared and initialized at the start of the body, but that I
have to explicitly destruct them.  Once again, the analogy is extremely
weak.

|>  I.e. IMO the body of the dtor must clean itself up before arranging for
|>  the subobject dtors to be called.  I believe that is the intent of the
|>  wording.

Why do you believe that is the intent?  Because you were present during
discussions?  I'm unaware of any discussions on this point, but I've not
always been that active.  In the absense of any explicit discussions, I
think we have to assume that the intent was to legislate the status quo
-- which was traditionally that the destructors of local variables were
invoked *after* the destructors of the sub-objects.

|>  It is certainly how I have always understood it.  IOWs the
|>  body of a direct base class dtor is not nested at the end of the derived
|>  class dtor but is entered in a way not dissimilar to the way exit is
|>  entered at the end of main.  Note that the behviour of your program is
|>  different if you call exit explicitly as opposed to its call implicitly.

Agreed.

I understand your argument -- personally, it doesn't make that much
difference to me which way is standardized, and there is a logic in what
you say.  However, traditionally compilers have done it otherwise, and
it doesn't seem to be a point big enough to be worth breaking with
tradition for me.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 2000/01/05
Raw View
In article <86zoum7suy.fsf@gabi-soft.de>,
  kanze@gabi-soft.de wrote:
[snip]
> However, traditionally compilers have done it otherwise, and
> it doesn't seem to be a point big enough to be worth breaking with
> tradition for me.
'Course, the Standard can easily ratify all existing practises (from
the sounds of it, there are compilers that do things both ways) by
simply stating that the order of destruction is unspecified (or,
perhaps, implementation-defined, so at least you know what'll happen).

--
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post
here.


Sent via Deja.com http://www.deja.com/
Before you buy.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 2000/01/06
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:

|>  In article <86k8lt7g9x.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
|>  >But the whole thing is emminently unclear.  Given the traditional
|>  >practice, and the fact that there was no vote negating traditional
|>  >practice, it seems certain that the *intent* was that local objects =
in a
|>  >destructor only be called after the destructors of the sub-objects h=
ave
|>  >been called.

|>  I think it is now clear that we need, at the very least, formal
|>  clarification by J16 & WG21.  Perhaps that should go as far as a defe=
ct
|>  report.

Well, it seemed clear enough to me until this discussion, but as I say,
that is probably because the alternative interpretations never occurred
to me.  An explicit statement one way or the other certainly wouldn't do
any harm.

|>  BTW despite the reference to C and the scope of a functions forma
|>  parameters, they in fact do not behave in a way that can be written o=
n
|>  entry to the body of a function (there is no defined order of
|>  initialisation, and there is a single sequence point separating them
|>  from the execution of the function.  In a way, the classic form of a =
C
|>  function definition better describes what happens.  I think what you
|>  were referring to was only intended to clarify the scope of the names=
 of
|>  the formal parameters in a definition (as opposed to the scope in a
|>  prototype)

Probably.  Globally, C never considered the issue, because it didn't
have to -- no constructors nor destructors.  I'm not sure that anyone in
C++ really considered it either.  My point of view is really only based
on what CFront did, and I suspect that in practice, no one every really
posed the question as to how it *should* be.  With the result that
current compilers differ.  Which is, in itself, probably grounds for a
request for clarification -- unless all of the vendors doing it one
particular way come out and says that it is a bug in their compiler.

Just out of curiosity, there are frequent contributors here from both
Sun and g++, and the two compilers do it differently.  Would anyone care
to comment as to whether the way they do it was a conscious decision, or
simple an accident of the implementation, and whether they consider it
an error in their compiler.

--=20
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@gabi-soft.de
Date: 2000/01/07
Raw View
Jim Hyslop <jim.hyslop@leitch.com> writes:

|>  In article <86zoum7suy.fsf@gabi-soft.de>,
|>    kanze@gabi-soft.de wrote:
|>  [snip]
|>  > However, traditionally compilers have done it otherwise, and
|>  > it doesn't seem to be a point big enough to be worth breaking with
|>  > tradition for me.
|>  'Course, the Standard can easily ratify all existing practises (from
|>  the sounds of it, there are compilers that do things both ways) by
|>  simply stating that the order of destruction is unspecified (or,
|>  perhaps, implementation-defined, so at least you know what'll happen).

It could.  IMHO, that would be the worst solution.  Although I could
live with it as well -- as I've already said, code depending on this
kind of thing is too fragile for my tastes.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/12/24
Raw View
In article <83t522$c8m$1@nnrp1.deja.com>, nimel@my-deja.com writes
>*** First here ***
>Creating Foo: 0
>Creating Foo: 1
>Creating Foo: 2
>*** Then here ***
>Creating Foo: 3
These four objects are destroyed in reverse order of construction.

>Copying Foo: 3 to 4
>Copying Foo: 3 to 5
>Copying Foo: 3 to 6

Yet, according to your code, these were not.

>Destroying Foo: 3
>*** And finally here
>Destroying Foo: 4
>Destroying Foo: 5
>Destroying Foo: 6
>Destroying Foo: 2
>Destroying Foo: 1
>Destroying Foo: 0

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/12/24
Raw View
On 24 Dec 99 16:11:21 GMT, Francis Glassborow
<francis@robinton.demon.co.uk> wrote:

: In article <83t522$c8m$1@nnrp1.deja.com>, nimel@my-deja.com writes
: >*** First here ***
: >Creating Foo: 0
: >Creating Foo: 1
: >Creating Foo: 2
: >*** Then here ***
: >Creating Foo: 3
: These four objects are destroyed in reverse order of construction.

Which means that the compiler conforms to the standard for array.

: >Copying Foo: 3 to 4
: >Copying Foo: 3 to 5
: >Copying Foo: 3 to 6
:
: Yet, according to your code, these were not.

Which has nothing to do with anything.  The standard makes no
requirements on the order of destruction of elements in a standard
container.

I have yet to find a compiler which gets array wrong.

The whole thing is haywire anyway.  Use destruct and placement new
to replace an item.  Destruction will be in reverse order of the
creation of the space for the objects not creation of the objects.

   Foo x;
   Foo y;
   x.~Foo();
   new (&x) Foo();

Yes the rules are reasonable and I have no desire for this example
to work other than it does.

John


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 1999/12/27
Raw View
Gerhard Menzl <gerhard.menzl@sea.ericsson.se> writes:

|>  Bill Wade wrote:

|>  > >The question is: if an object of automatic storage is declared in
|>  > >the body of the destructor of X, is the destructor of that object
|>  > >guaranteed to be executed before the destructors of the members
|>  > >of X?

|>  > Emphatically yes.  However I can't find chapter and
|>  > verse. 12.6.2/5 makes it clear that the body of the constructor is
|>  > the last thing that happens during construction.  I can't find
|>  > anything in the standard that explicitly says that sub-objects
|>  > aren't destroyed until after the body of the destructor exits.
|>  > This may be a defect in the standard.  Since you have a compiler
|>  > doing the wrong thing you may want to look at the defect list, and
|>  > if it isn't there, submit a defect report.

|>  To me 12.4/6, which states that the order of destruction is the reverse
|>  order of construction, is pretty clear. The issue I was uncertain about
|>  (and where my compiler is wrong) is the order of destruction of an
|>  automatic object in a class destructor and a member of the same class.

Right.  12.4/6 specifies the order of destruction of sub-objects only.
The only statement it makes concerning automatic objects in the
destructor is the indirect one that it is the outer object destructor
which calls the destrcutors for the sub-objects, which implies very
strongly (IMHO, anyway) that the destructors of the automatic objects
are only called *after* the destructors of the sub-objects.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 1999/12/27
Raw View
"Bill Wade" <bill.wade@stoner.com> writes:

|>  Gerhard Menzl (SEA) wrote in message
|>  <06A8EA4CE008D3119CFF0008C75DA44C8C62CD@eatvint902>...
|>  >The question is: if an object of automatic
|>  >storage is declared in the body of the destructor of X, is the destructor
|>  >of that object guaranteed to be executed before the destructors of the
|>  >members of X?

|>  Emphatically yes.  However I can't find chapter and verse. 12.6.2/5
|>  makes it clear that the body of the constructor is the last thing
|>  that happens during construction.  I can't find anything in the
|>  standard that explicitly says that sub-objects aren't destroyed
|>  until after the body of the destructor exits.

In fact, the standard says explicitly the opposite: it is the destructor
of the outer object which calls the destructors of the sub-objects.

|>  This may be a defect
|>  in the standard.  Since you have a compiler doing the wrong thing
|>  you may want to look at the defect list, and if it isn't there,
|>  submit a defect report.

I think in fact that the standard is clear enough in this regard, but I
suppose the question is arguable.  If there is a defect, however, it is
simply the lack of clarity.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 1999/12/28
Raw View
"Gerhard Menzl (SEA)" <Gerhard.Menzl@sea.ericsson.se> writes:

|>  The order of destruction for classes and members is clearly defined in
|>  12.4/6 as the reverse order of construction; i.e. for a class X the order
|>  of execution is:

|>     1. Destructor of X,
|>     2. Destructors of members of X in reverse order of declaration,

|>  Next would be direct base classes and virtual base classes, but these are
|>  not relevant in this context. The question is: if an object of automatic
|>  storage is declared in the body of the destructor of X, is the destructor
|>  of that object guaranteed to be executed before the destructors of the
|>  members of X?

I think the contrary, although I can't quote the standard to back it up.
Traditionally, at any rate, the invocation of the base and member class
destructors has been considered to occur from the derived class
destructor.  I suppose that the standard could be clearer, but the
paragraph that you cite says explicitly that "A destructor for class X
calls the destructors for X's direct members, the destructors for X's
direct base classes and, if X is the type of the most derived class, its
destructor calls the destructors for X's virtual base classes."  This
seems fairly clear to me that the member destructors are called from
within the outer class destructor, before leaving the scope of the outer
class destructor.

|>  To illustrate the question:

|>     #include <iostream>

|>     struct M {
|>        ~M () {
|>           std::cout << "M::~M()" << std::endl; }
|>     };

|>     struct G {
|>        ~G () {
|>           std::cout << "G::~G()" << std::endl; }
|>     };

|>     struct C {
|>        ~C () {
|>           std::cout << "C::~C()" << std::endl;
|>           G g; }

|>        M m;
|>     };

|>     int main ()
|>     {
|>        C c;
|>        return 0;
|>     }

|>  I would expect the output of this program to be:
|>
|>     C::~C()
|>     G::~G()
|>     M::~M()

My interpretation of the standard would give:

    C::~C()
    M::~M()
    G::~G()

This is also what I would expect intuitively, and I *think* that this is
what CFront did, and I *think* it is what older versions of g++ did.  In
fact, the compilers I currently have access to vary: g++ (2.95) gives
the order you expect, and Sun CC (5.0) the order I expected.  I would
consider this a (minor) bug in g++.

|>  and frankly, I would find C++ pretty useless if it wasn't. 12.4/10
|>  mandates that destructors for automatic objects are invoked when its
|>  block scope is left. In the above example, that block is the body of
|>  C::~C(). Am I right to deduce from this that the complete execution
|>  of C::~C() includes the execution of G::~G(), and M::~M() must not
|>  be executed before that?

The question is whether the destructors of the base and member classes
are to be invoked before the block scope of the derived class is left.
As I say, I would expect this to be the case, and my interpretation of
the standard confirms this.  (To tell the truth, before your posting, it
never occured to me that it could be otherwise.)

|>  The background: I have a compiler that produces a program which emits:

|>     C::~C()
|>     M::~M()
|>     G::~G()

|>  and I want to be very certain before I conclude that said compiler
|>  is a dangerous piece of junk and tell he manufacturer.

Well, I certainly wouldn't call it a dangerous piece of junk just
because it implements the standard:-).  Even if the standard confirmed
what you want, I would expect vendors like Sun to continue to offer this
version, at least as an option, for reasons of backwards compatibility.
Similarly, I don't consider g++ a dangerous piece of junk just because
their interpretation of the standard isn't conform avec mine.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@gabi-soft.de
Date: 1999/12/28
Raw View
jpotter@falcon.lhup.edu (John Potter) writes:

|>  I have yet to find a compiler which gets array wrong.

Me neither.  Just to be sure, I double checked g++ (2.95) and Sun CC
(5.0): both get it right.  As expected: I know that earlier versions,
going back as far as I can remember, also got it right.

|>  The whole thing is haywire anyway.  Use destruct and placement new
|>  to replace an item.  Destruction will be in reverse order of the
|>  creation of the space for the objects not creation of the objects.

|>     Foo x;
|>     Foo y;
|>     x.~Foo();
|>     new (&x) Foo();

|>  Yes the rules are reasonable and I have no desire for this example
|>  to work other than it does.

Never the less, I think that the standard requires a different order.
But I think I'd consider this a bug in the standard, and not in the
compilers:-).

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/12/28
Raw View
On 27 Dec 1999 17:39:40 GMT, kanze@gabi-soft.de wrote:

:
: "Bill Wade" <bill.wade@stoner.com> writes:
:
: |>  However I can't find chapter and verse. 12.6.2/5
: |>  makes it clear that the body of the constructor is the last thing
: |>  that happens during construction.  I can't find anything in the
: |>  standard that explicitly says that sub-objects aren't destroyed
: |>  until after the body of the destructor exits.
:
: In fact, the standard says explicitly the opposite: it is the destructor
: of the outer object which calls the destructors of the sub-objects.

But, it is also obvious that it is the constructor of the outer object
which calls the constructors of the sub-objects.  It's parameters are
available.  It all happens prior to entering the body of the outer ctor.

: |>  This may be a defect
: |>  in the standard.  Since you have a compiler doing the wrong thing
: |>  you may want to look at the defect list, and if it isn't there,
: |>  submit a defect report.
:
: I think in fact that the standard is clear enough in this regard, but I
: suppose the question is arguable.  If there is a defect, however, it is
: simply the lack of clarity.

I don't think so.  With your reading (no arguement with it), it is
clear that the destructors of the sub-objects may be called at the
beginning of the outer detor, prior to constructing any automatics
or executing the code of the body.  This is clearly unsat.  The
intent is for destruction to be the reverse of construction and the
lack of a clear statement to that effect is a defect.  Construction
of sub-objects occurs prior to the beginning brace of the outer ctor,
and destruction of sub-objects should occur after the ending brace of
the outer detor.  The use of "calls" is too open ended for a standard.
This also seems to violate the general concept that all non-dynamic
objects which exist when another object is created will continue to
exist through the destruction of the other object.  Ie. non-dynamic
object lifetimes are nested.

John
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/12/28
Raw View
In article <3867f61d.40735427@news.csrlink.net>, John Potter
<jpotter@falcon.lhup.edu> writes
>I don't think so.  With your reading (no arguement with it), it is
>clear that the destructors of the sub-objects may be called at the
>beginning of the outer detor, prior to constructing any automatics
>or executing the code of the body.  This is clearly unsat.  The
>intent is for destruction to be the reverse of construction and the
>lack of a clear statement to that effect is a defect.  Construction
>of sub-objects occurs prior to the beginning brace of the outer ctor,
>and destruction of sub-objects should occur after the ending brace of
>the outer detor.  The use of "calls" is too open ended for a standard.
>This also seems to violate the general concept that all non-dynamic
>objects which exist when another object is created will continue to
>exist through the destruction of the other object.  Ie. non-dynamic
>object lifetimes are nested.

Executing the body of a ctor is the final action before return.  I think
this is well defined and universally implemented.  What is less clear is
how a dtor should work.  To get strict reverse order the body of a dtor
should be run in its entirety before the remaining action is undertaken
(executing dtors of sub-objects etc.) and finally memory should be
deallocated (just as memory allocation is the first action of a ctor)



Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/12/28
Raw View
In article <86902goalu.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
>The question is whether the destructors of the base and member classes
>are to be invoked before the block scope of the derived class is left.
>As I say, I would expect this to be the case, and my interpretation of
>the standard confirms this.  (To tell the truth, before your posting, it
>never occured to me that it could be otherwise

While I assumed otherwise.  Entry to the block scope of a ctor only
occurs after direct base class and member subobjects have been fully
ctored.  I intuitively expect the destruction process to work in
reverse.

Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: zivca@netvision.net.il (Ziv Caspi)
Date: 1999/12/30
Raw View
On 28 Dec 1999 16:43:12 GMT, Francis Glassborow
<francis@robinton.demon.co.uk> wrote:

>While I assumed otherwise.  Entry to the block scope of a ctor only
>occurs after direct base class and member subobjects have been fully
>ctored.  I intuitively expect the destruction process to work in
>reverse.

Forgive my intrusion: Does this mean that in the following code,
~R() must not access ref?:

struct B {};

struct R {
  R( B& b ) : ref(b) {}
  ~R() { /* Access ref */ }
  B& ref;
};

struct D : public B {
  ~D() { R r( static_cast<B&>(*this) ); }
};


---------------------------------------------
Ziv Caspi
zivca@netvision.net.il
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ron Natalie <ron@sensor.com>
Date: 1999/12/31
Raw View


Ziv Caspi wrote:
>
> Forgive my intrusion: Does this mean that in the following code,
> ~R() must not access ref?:
>

Eh?  Why not.  The R destructor is run before the B part
of the referred to object is destroyed.

Nothing happens during destruction to the "ref" member.



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/12/31
Raw View
In article <3869b766.680466639@news.netvision.net.il>, Ziv Caspi
<zivca@netvision.net.il> writes
>Forgive my intrusion: Does this mean that in the following code,
>~R() must not access ref?:
>
>struct B {};
>
>struct R {
>  R( B& b ) : ref(b) {}
>  ~R() { /* Access ref */ }

Well, I do not see why it should not (in practice) because ref exists
until the memory storing it is released.  Put it another way, according
to my interpretation, ref is initialised before entry to the body of the
ctor and so will not be 'uninitialised' until after exit from the body
of the dtor.

>  B& ref;
>};

>
>struct D : public B {
>  ~D() { R r( static_cast<B&>(*this) ); }
>};

And here, according to my view, the dtor for B is not called until after
exit from the body of D's dtor - no problem that I can see other than
having code that will be very hard to maintain.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: kanze@gabi-soft.de
Date: 2000/01/01
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:

|>  In article <3867f61d.40735427@news.csrlink.net>, John Potter
|>  <jpotter@falcon.lhup.edu> writes
|>  >I don't think so.  With your reading (no arguement with it), it is
|>  >clear that the destructors of the sub-objects may be called at the
|>  >beginning of the outer detor, prior to constructing any automatics
|>  >or executing the code of the body.  This is clearly unsat.  The
|>  >intent is for destruction to be the reverse of construction and the
|>  >lack of a clear statement to that effect is a defect.  Construction
|>  >of sub-objects occurs prior to the beginning brace of the outer ctor,
|>  >and destruction of sub-objects should occur after the ending brace of
|>  >the outer detor.  The use of "calls" is too open ended for a standard.
|>  >This also seems to violate the general concept that all non-dynamic
|>  >objects which exist when another object is created will continue to
|>  >exist through the destruction of the other object.  Ie. non-dynamic
|>  >object lifetimes are nested.

|>  Executing the body of a ctor is the final action before return.

I think it would be more accurate to say that executing the body of the
constructor is the only action -- the compiler generates implicite calls
to the sub-object constructors at the start of the body.

At least, this is the way I have always been taught.

|>  I think
|>  this is well defined and universally implemented.  What is less clear is
|>  how a dtor should work.  To get strict reverse order the body of a dtor
|>  should be run in its entirety before the remaining action is undertaken
|>  (executing dtors of sub-objects etc.) and finally memory should be
|>  deallocated (just as memory allocation is the first action of a ctor)

Before making such statements, it is necessary to define what the body
of a function consists of.  Why do you not say, for example, that the
compiler generates calls to the constructors of the sub-objects at the
start of the body of the constructor, the same as it generates calls to
the destructors of the sub-objects at the end of the body.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 2000/01/01
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:

|>  In article <86902goalu.fsf@gabi-soft.de>, kanze@gabi-soft.de writes
|>  >The question is whether the destructors of the base and member classes
|>  >are to be invoked before the block scope of the derived class is left.
|>  >As I say, I would expect this to be the case, and my interpretation of
|>  >the standard confirms this.  (To tell the truth, before your posting, it
|>  >never occured to me that it could be otherwise

|>  While I assumed otherwise.  Entry to the block scope of a ctor only
|>  occurs after direct base class and member subobjects have been fully
|>  ctored.  I intuitively expect the destruction process to work in
|>  reverse.

Can you show me where in the standard it says that entry to the block
scope of a constructor only occurs after the direct base class and
member sub-objects have been fully constructed.  In C, at least,
function arguments are considered to be in scope "as if" they were
declared at the start of the function body.  (I can find no
specification in the C++ standard as to the scope of function arguments,
but I probably just don't know where to look.)  Since I can use function
arguments in the initialization clauses of the sub-objects, I conclude
that the constructors must be called at the start of the body.

But the whole thing is emminently unclear.  Given the traditional
practice, and the fact that there was no vote negating traditional
practice, it seems certain that the *intent* was that local objects in a
destructor only be called after the destructors of the sub-objects have
been called.

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.de
Date: 2000/01/02
Raw View
jpotter@falcon.lhup.edu (John Potter) writes:

|>  On 27 Dec 1999 17:39:40 GMT, kanze@gabi-soft.de wrote:

|>  : "Bill Wade" <bill.wade@stoner.com> writes:

|>  : |>  However I can't find chapter and verse. 12.6.2/5
|>  : |>  makes it clear that the body of the constructor is the last thing
|>  : |>  that happens during construction.  I can't find anything in the
|>  : |>  standard that explicitly says that sub-objects aren't destroyed
|>  : |>  until after the body of the destructor exits.

|>  : In fact, the standard says explicitly the opposite: it is the destructor
|>  : of the outer object which calls the destructors of the sub-objects.

|>  But, it is also obvious that it is the constructor of the outer object
|>  which calls the constructors of the sub-objects.  It's parameters are
|>  available.  It all happens prior to entering the body of the outer ctor.

The argument of parallelism to the constructor did occur to me.  But I
don't see the problem: why do you say that calling the constructors of
the sub-objects happens prior to entering the body of the outer
constructor.  It happens prior to executing the first user instruction
in the body, but I don't see this as necessarily occuring *prior* to
entering the body.  (To be more precise, of course, we'd have to define
what is meant be "entering the body" of a function.)

|>  : |>  This may be a defect
|>  : |>  in the standard.  Since you have a compiler doing the wrong thing
|>  : |>  you may want to look at the defect list, and if it isn't there,
|>  : |>  submit a defect report.

|>  : I think in fact that the standard is clear enough in this regard, but I
|>  : suppose the question is arguable.  If there is a defect, however, it is
|>  : simply the lack of clarity.

|>  I don't think so.  With your reading (no arguement with it), it is
|>  clear that the destructors of the sub-objects may be called at the
|>  beginning of the outer detor, prior to constructing any automatics
|>  or executing the code of the body.

The one sentence I quoted allows this.  The following sentences specify
where in the destructor the other destructors must be called.

|>  This is clearly unsat.  The
|>  intent is for destruction to be the reverse of construction and the
|>  lack of a clear statement to that effect is a defect.  Construction
|>  of sub-objects occurs prior to the beginning brace of the outer ctor,
|>  and destruction of sub-objects should occur after the ending brace of
|>  the outer detor.  The use of "calls" is too open ended for a standard.
|>  This also seems to violate the general concept that all non-dynamic
|>  objects which exist when another object is created will continue to
|>  exist through the destruction of the other object.  Ie. non-dynamic
|>  object lifetimes are nested.

This is the first time I've heard of this general concept.  Are you
trying to say that in the following program:

    void
    f()
    {
        Class1 aLocalObject ;
        static Class2 aStaticLocalObject ;
    }

the lifetime of aLocalObject must be extended until after the
destruction of aStaticLocalObject?  This is not the way I interpret the
standard.

I'm perfectly willing to admit that the standard is perhaps not as clear
as it should be here.  I'll also admit that my own interpretation is
colored by the way C++ compilers have traditionally worked.  On the
other hand, I remember no discussion in the committee with regards to
this point -- in the absence of such, I can hardly believe that it was
the intent of the committee to break "traditional" implementations.
(Many changes do break traditional implementations, but all of these
changes were discussed as such, with an expressed vote on the change.)

--
James Kanze                         mailto:James.Kanze@gabi-soft.de
Conseils en informatique orientie objet/
                  Beratung in Objekt orientierter Datenverarbeitung
Ziegelh|ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 2000/01/02
Raw View
On 1 Jan 2000 21:50:55 GMT, kanze@gabi-soft.de wrote:

:
: Francis Glassborow <francis@robinton.demon.co.uk> writes:
:
: |>  Executing the body of a ctor is the final action before return.
:
: I think it would be more accurate to say that executing the body of the
: constructor is the only action -- the compiler generates implicite calls
: to the sub-object constructors at the start of the body.
:
: At least, this is the way I have always been taught.
:
: |>  I think
: |>  this is well defined and universally implemented.  What is less clear is
: |>  how a dtor should work.  To get strict reverse order the body of a dtor
: |>  should be run in its entirety before the remaining action is undertaken
: |>  (executing dtors of sub-objects etc.) and finally memory should be
: |>  deallocated (just as memory allocation is the first action of a ctor)
:
: Before making such statements, it is necessary to define what the body
: of a function consists of.  Why do you not say, for example, that the
: compiler generates calls to the constructors of the sub-objects at the
: start of the body of the constructor, the same as it generates calls to
: the destructors of the sub-objects at the end of the body.

Because it just does not fit in with everything else.  Things are
normally destroyed in the reverse order of construction.

struct S1 { void f(); };
struct S2 { S1& v; S2 (S1& i) : v(i) { v.f(); } ~S2 () { v.f(); } };
struct S3 { S1 s; ~S3 () { S2 x(s); } };

You see:
   S2 (S1& i) { v.S1(i); v.f(); }
   ~S2 { v.f(); v.~S1(); }
   ~S3 { x.S2(s); s.~S1(); x.~S2(); }

I see:
   S2 (S1& i) { v.S1(i); { v.f(); } }
   ~S2 { { v.f(); } v.~S1(); }
   ~S3 { { x.S2(s); x.~S2(); } s.~S1(); }

This is consistent with:
   ~S2 { v.f(); } : v()
   ~S3 { S2 x(s); } : s()

The standard seems to support your view; however, there are compilers
which support both views.  If the standard says what was intended, it
is a complaint only.  If the standard does not say what was intended,
it is a defect.  In either case, there are broken compilers which
demands clarification.

In 12.6.2/5 the order of construction and execution of the body of a
ctor is clearly stated.  It never mentions calling a ctor.  The order
of destruction is clearly stated to be the reverse of construction, but
nowhere does it mention execution of the body of the dtor.

John
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/12/22
Raw View
Gerhard Menzl (SEA) wrote in message
<06A8EA4CE008D3119CFF0008C75DA44C8C62CD@eatvint902>...
>The question is: if an object of automatic
>storage is declared in the body of the destructor of X, is the destructor
>of that object guaranteed to be executed before the destructors of the
>members of X?

Emphatically yes.  However I can't find chapter and verse. 12.6.2/5 makes it
clear that the body of the constructor is the last thing that happens during
construction.  I can't find anything in the standard that explicitly says
that sub-objects aren't destroyed until after the body of the destructor
exits.  This may be a defect in the standard.  Since you have a compiler
doing the wrong thing you may want to look at the defect list, and if it
isn't there, submit a defect report.

You can find the defect lists and info on how to submit a defect report in
the FAQ.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: mborgerd@my-deja.com
Date: 1999/12/22
Raw View
In article <06A8EA4CE008D3119CFF0008C75DA44C8C62CD@eatvint902>,
  "Gerhard Menzl (SEA)" <Gerhard.Menzl@sea.ericsson.se> wrote:
> The order of destruction for classes and members is clearly defined in
> 12.4/6 as the reverse order of construction; i.e. for a class X the
[snip]
> 12.4/10  mandates
> that destructors for automatic objects are invoked when its block
scope is
> left. In the above example, that block is the body of C::~C(). Am I
right
> to deduce from this that the complete execution of C::~C() includes
the
> execution of G::~G(), and M::~M() must not be executed before that?
>
I interperet the standard the same way.  Any other implementation seems
flawed.  Your logic is well supported and references the standard
appropriately.  I think you are well founded in complaining to the
compiler maker.

--
Mark Borgerding
mborgerding at acm dot org


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gerhard Menzl <gerhard.menzl@sea.ericsson.se>
Date: 1999/12/22
Raw View
Bill Wade wrote:

> >The question is: if an object of automatic
> >storage is declared in the body of the destructor of X, is the destructor
> >of that object guaranteed to be executed before the destructors of the
> >members of X?
>
> Emphatically yes.  However I can't find chapter and verse. 12.6.2/5 makes
> it clear that the body of the constructor is the last thing that happens
> during construction.  I can't find anything in the standard that
> explicitly says that sub-objects aren't destroyed until after the body of
> the destructor exits.  This may be a defect in the standard.  Since you
> have a compiler doing the wrong thing you may want to look at the defect
> list, and if it isn't there, submit a defect report.

To me 12.4/6, which states that the order of destruction is the reverse
order of construction, is pretty clear. The issue I was uncertain about
(and where my compiler is wrong) is the order of destruction of an
automatic object in a class destructor and a member of the same class.

Gerhard Menzl


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/12/23
Raw View
In article <3860E80D.C3E24BD7@sea.ericsson.se>, Gerhard Menzl <gerhard.m
enzl@sea.ericsson.se> writes
>To me 12.4/6, which states that the order of destruction is the reverse
>order of construction, is pretty clear. The issue I was uncertain about
>(and where my compiler is wrong) is the order of destruction of an
>automatic object in a class destructor and a member of the same class.

On a completely orthogonal issue, how many compilers destroy arrays in
the correct order?


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: nimel@my-deja.com
Date: 1999/12/24
Raw View
In article <ubIuKJAH1YY4Ew8P@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> On a completely orthogonal issue, how many compilers destroy arrays in
> the correct order?

What is correct order? Following is a test program and its output
for the compiler I use. Looks ok to me.

#include <iostream>
#include <vector>

using std::cout;
using std::vector;

class Foo
{
public:
  Foo() : m_id(s_objCount++)
  {
    cout << "Creating Foo: " << m_id << '\n';
  }
  Foo(const Foo& f) : m_id(s_objCount++)
  {
    cout << "Copying Foo: " << f.m_id << " to " << m_id << '\n';
  }
  ~Foo()
  {
    cout << "Destroying Foo: " << m_id << '\n';
  }
private:
  static int s_objCount;
  int m_id;
};

int Foo::s_objCount = 0;

int main()
{
  cout << "*** First here ***\n";
  Foo x[3];
  cout << "*** Then here ***\n";
  vector<Foo> v(3);
  cout << "*** And finally here\n";
  return 0;
}

*** First here ***
Creating Foo: 0
Creating Foo: 1
Creating Foo: 2
*** Then here ***
Creating Foo: 3
Copying Foo: 3 to 4
Copying Foo: 3 to 5
Copying Foo: 3 to 6
Destroying Foo: 3
*** And finally here
Destroying Foo: 4
Destroying Foo: 5
Destroying Foo: 6
Destroying Foo: 2
Destroying Foo: 1
Destroying Foo: 0


Sent via Deja.com http://www.deja.com/
Before you buy.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Gerhard Menzl (SEA)" <Gerhard.Menzl@sea.ericsson.se>
Date: 1999/12/20
Raw View
The order of destruction for classes and members is clearly defined in
12.4/6 as the reverse order of construction; i.e. for a class X the order
of execution is:

   1. Destructor of X,
   2. Destructors of members of X in reverse order of declaration,

Next would be direct base classes and virtual base classes, but these are
not relevant in this context. The question is: if an object of automatic
storage is declared in the body of the destructor of X, is the destructor
of that object guaranteed to be executed before the destructors of the
members of X?

To illustrate the question:

   #include <iostream>

   struct M
   {
      ~M ()
      {
         std::cout << "M::~M()" << std::endl;
      }
   };

   struct G
   {
      ~G ()
      {
         std::cout << "G::~G()" << std::endl;
      }
   };

   struct C
   {
      ~C ()
      {
         std::cout << "C::~C()" << std::endl;
         G g;
      }

      M m;
   };

   int main ()
   {
      C c;
      return 0;
   }

I would expect the output of this program to be:

   C::~C()
   G::~G()
   M::~M()

and frankly, I would find C++ pretty useless if it wasn't. 12.4/10 mandates
that destructors for automatic objects are invoked when its block scope is
left. In the above example, that block is the body of C::~C(). Am I right
to deduce from this that the complete execution of C::~C() includes the
execution of G::~G(), and M::~M() must not be executed before that?

The background: I have a compiler that produces a program which emits:

   C::~C()
   M::~M()
   G::~G()

and I want to be very certain before I conclude that said compiler is a
dangerous piece of junk and tell he manufacturer.

Gerhard Menzl
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]