[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]

Re: "delete", "destroy", "reclaim", and "p->Heaper::~Heaper();"

> From: vlad!mark (Mark S. Miller)
>    (Has all of this "delete" stuff happened because I didn't make that
>     clear in the documentation?)
> No.  I actually understood all that about how the Bomb package works.
> [] I should
> have said that C++ doesn't allow "delete" to be *silently* refused.
> "delete" also has other problems (mostly cfront, not language def).

Oh, right.  An object may be serving more than one client, and wish
to transparently refuse destruction unless it's the last client that
makes the request.  Of course.  (Duhhhhhh....)

> (Although I'm still curious about what happens if a member destructor
> BLASTs--is it as bad as if a member constructor BLASTs?)

The deallocation of the storage is skipped.  If the destructor which BLASTS
is the destructor of a superclass, the vtable pointer has been replaced
with that of the superclass.  The object is now a valid instance of the
class whose destructor BLASTed, unless:

 - That destructor has broken it, or

 - It wasn't a valid instance when that destructor was entered.

So BLASTing from a destructor is also an assertion that either the object
is still a valid instance of the class whose destructor BLASTed (at least
valid enough to handle further interaction) or the application should
immediately terminate.

A "gotcha" to watch for:  Destructors are called by the constructor bomb
mechanism when construction fails.  So if a class has constructors which
may fail, the destructor (at that level of the class hierarchy only) must
be careful not to BLAST out of the failed construction with an invalid
object state.

The only semantic problem with BLASTING from destruction is that it may
result in an object of a superclass type being held by a pointer to one
of its subclasses.  This presents essentially the same case as holding a
pointer that has been incorrectly cast to a derived type:

 - The object "knows" its new type.  getCategory(), the destructor,
   and any other virtual member functions common to the original and
   the current (superclass) type will correctly exhibit the appropriate
   behavior for the current type.

 - Calling a virtual member function of the original type that is not
   inherited by the current type will jump indirect off something beyond
   the end of the vtable.  This may be an invalid pointer, a pointer to
   a member function of some other class, or who-knows-what.

 - Calling a non-virtual member function will get the member function
   appropriate to the type of the pointer, ignoring the type of the
   actual object.  (Though in this case storage has been allocated for
   the larger object's member variables, so modifying a member variable
   won't trash some unrelated data.)

This condition is (initially) localized to the ACTION of the SHIELD_UP
that catches the BLAST from the destructor, and can't escape to the rest
of the code unless the ACTION permits it.

So though the two worms in this can are reasonably well-trained, they're
slimy enough that catching BLASTs from destructors is something worth
avoiding.  Your solution of providing a conventional member function
whose semantics is conditional destruction, and reserving the destructor
for actually destroying the object, is great stuff.