[Prev][Next][Index]

alternative to "trashed" (a real message this time)



Dave,

Apologies to you and everyone for sending your message again.  I typed
the wrong characters...

   > I agree that the constructor can't assume the invariant.  This argues
   > that perhaps some special syntax should be used so that users
   > don't get confused.

   I'm not sure I understand; I thought that C++ constructors do have a
   fairly special syntax.

I meant special specification syntax.

Thanks for the example and reference to show you can invoke a destructor
and operator delete explictily.  This argues that one should just specify
the "filling in" on the part of the constructor, and the "anti-filling in"
of the destructor.

   There is a potential complicated difficulty here, as destructors are
   called on objects with virtual functions and base classes, the vptr
   must "swing" to that of the base class before executing the base
   class' destructor.  Is the destructor required to restore it to its
   original value, to make the second invocation work correctly?  The ARM
   is fairly silent on this point.  This question is relevant to
   something we're working on, too; I may query comp.std.c++ and see if
   any real language lawyers care to respond.

That seems like an implementation issue to me.  Clearly it should be
restored correctly...  one would hope that eventually implementations
would do that.

   >>   Symmetrically, destructors are distinguished member functions that get
   >>   to assume the class invariant on entry, but aren't required to
   >>   maintain them on exit.  Thus, if a class has a non-trivial invariant,
   >>   it is necessarily illegal to call a member function on an object after
   >>   its destructor is called; you can't establish the pre-condition that
   >>   the invariant holds!

   > But it's even illegal to call a member function if the invariant is trivial
   > (:-).

   I'm not sure I get your meaning; are you saying that it's illegal to
   call a member function on an object after its destructor has been
   called, even if the object has a trivial invariant the the destructor
   didn't invalidate?

No, I was saying that it's just plain wrong to call a member function after
the destructor is called.  I can't imagine that any sensible verification
logic would allow you to do anything on an object that has had its destructor
called.  My point was that the triviality of the class's invariant has
nothing to do with it.

   You could just define things this way; I was
   proposing a rationale for what distinguishes the destructor from other
   member functions.  If we accept that calling a destructor without
   doing a delete, via "p->~T()",  is legal, then there is especially
   good reason to treat the destructor differently from any other member
   function.  Usually, it will happen to be different from other member
   functions in that it doesn't preserve the class invariant, in which
   case no member function can be called on an object after the
   destructor has.  But this is not always necessary, as in the case
   we're discussing.

I agree that one can call the destructor without calling delete.
I'm not sure I want to be able to specify that...  Is there any good reason
for doing it?

   > The only thing that worries me still is that one can construct an
   > object (on the run-time stack) without using new,
   > and destroy an object implictly by leaving a block.
   > 	{ Stack x;
   >	  ...
   >	}

   This seems to me exactly the reason for *not* mixing up the
   specification of the storage state with the effects of constructors
   and destructors; they really are complete separate in C++.  If I write
   a class T, there is *no way* I can keep a client from allocating
   instances of T on both the stack in the heap.  The semantic meaning of
   "new T" *really is* the composition of a call to "::operator new"
   followed by a constructor, and "delete p" really is a destructor
   invocation followed by "::operator delete".  So I persist in thinking
   that the specification of "operator new" and "operator delete" is
   where you should deal with FRESH and TRASHED.

   Think of it this way: C++ really isn't that different from C.  In C,
   you would call "malloc", and then, by convention, call an initialization
   routine to establish an invariant.  Similarly, you might call a
   destruction routine followed by "free".  C++ just codifies these
   conventions.

I guess I have to agree with this.  This is the position I started with.
But it does seem strange with respect to the other specs in a class.

Is the stuff you refer to as the "malloc plumber" a paper on specifying
storage allocation?

	Gary






Reference(s):