Topic: Access control with private virtual destructors


Author: hendrik@vedge.com (Hendrik Boom)
Date: Thu, 04 Nov 1993 14:49:13 GMT
Raw View
rfg@netcom.com (Ronald F. Guilmette) writes:
: In article <CF6w8F.xD@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
: >
: > Destructors are not ordinary functions. They are not inherited.
:
: Wrong.  They obviously *are* inherited, or else making them virtual would
: never make any sense... but doing so is *recommended*!

Inheritance and virtualness work in opposite directions.

If D inherits f from B, the f that is used on a D object is obtained from
the f defined in B.

But if f is virtual, the f used on B is the f from D (if the actual objects
happens to be of that derived type).
:
: >Instead, the derived class destructor must call the body of the
: >base class destructor.
:
: That seems apparent, but we are talking about the (forthcomming) standard
: here... So I'll ask my usual question "Where do it say that?"

between the lines?

:
: --
:
: -- Ronald F. Guilmette, Sunnyvale, California -------------------------------
: ------ domain address: rfg@netcom.com ---------------------------------------
: ------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
--
-------------------------------------------------------
Try one or more of the following addresses to reply.
at work: hendrik@vedge.com,  iros1!vedge!hendrik
at home: uunet!ozrout!topoi!hendrik




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 1 Nov 1993 06:16:46 GMT
Raw View
In article <2a1j5e$aso@senator-bedfellow.MIT.EDU> jud@ceci.mit.EDU (Judson Harward) writes:
>
>class B
>{
>    private:
> virtual ~B() { ... }
>
>    public:
>        Destroy() { ... delete this; };
>};
>
>class D : public B
>{
>    private:
> ~D() {}
>};
>
>...  But does ~D have or need access to ~B?

That's a very good question.  It certainly is not documented (at least
not clearly) anywhere, but the majority of existing implementations *do*
quietly generate implicit calls to all base class destructors for any
given derived class destructor.  Note that this happens even in cases
where the derived class destructor is itself implicitly generated...
which occasionally leads to surprizes:

 struct B { private: ~B(); };
 struct D : public B { }; // hummm...

 void foobar (D *p)
 {
  delete p; // error!!??
 }

What's really interesting about the above example is that some compilers
don't even need to see any code which *uses* the derived class destructor
before they complain.  Some compilers will issue an error on the line
marked `hummm....' even if there are no calls whatsoever to the derived
class constructor anywhere else in the entire translation unit.

Which behavior is most "correct"?  Which behavior is most "desirable"?
You be the judge.

>A strict reading of the ARM would seem to imply that ~D does not have
>access to ~B...

That's 100% correct.

> but this is paradoxical when ~D is called via ~B.

The ~D destructor is NEVER "called via ~B".  I don't know why you would
think that it ever would be.

> Sun's 4.1.3 cfront 3.0.1 derived C++ permits the above construction.
>Borland's C++ 4.0 requires making ~B protected.  Which is correct?

That's pretty much the same problem as I illustrated in my example above.
Should a compiler issue an error even if we never make any calls to ~D()
or should it instead wait until some code later in the same translation
unit actually *references* (either explicitly or implicitly) ~D?

I don't know.

Separately, is the answer to that last question affected by whether ~D()
is supplied explicitly by the user or supplied implicitly by the compiler?

Again, I don't know.  I wish I did.

--

-- Ronald F. Guilmette, Sunnyvale, California -------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 1 Nov 1993 06:20:32 GMT
Raw View
In article <CF6w8F.xD@ucc.su.OZ.AU> maxtal@physics.su.OZ.AU (John Max Skaller) writes:
>In article <2a1j5e$aso@senator-bedfellow.MIT.EDU> jud@ceci.mit.EDU (Judson Harward) writes:
>>
>>class B
>>{
>>    private:
>> virtual ~B() { ... }
>>
>>    public:
>>        Destroy() { ... delete this; };
>>};
>>
>>class D : public B
>>{
>>    private:
>> ~D() {}
>>};
>>
>> Sun's 4.1.3 cfront 3.0.1 derived C++ permits the above construction.
>>Borland's C++ 4.0 requires making ~B protected.  Which is correct?
>
> Destructors are not ordinary functions. They are not inherited.

Wrong.  They obviously *are* inherited, or else making them virtual would
never make any sense... but doing so is *recommended*!

>Instead, the derived class destructor must call the body of the
>base class destructor.

That seems apparent, but we are talking about the (forthcomming) standard
here... So I'll ask my usual question "Where do it say that?"

--

-- Ronald F. Guilmette, Sunnyvale, California -------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Mon, 1 Nov 1993 07:23:35 GMT
Raw View
In article <rfgCFsus0.9uL@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <2a1j5e$aso@senator-bedfellow.MIT.EDU> jud@ceci.mit.EDU (Judson Harward) writes:
>>
>>class B
>>{
>>    private:
>> virtual ~B() { ... }
>>
>>    public:
>>        Destroy() { ... delete this; };
>>};
>>
>>class D : public B
>>{
>>    private:
>> ~D() {}
>>};
>>
>>...  But does ~D have or need access to ~B?
>
>That's a very good question.  It certainly is not documented (at least
>not clearly) anywhere, but the majority of existing implementations *do*
>quietly generate implicit calls to all base class destructors for any
>given derived class destructor.

 Indeed. And the problem is that there is no coherent object
model. My temporary model is clear, that complete objects
exist only between constructor and destructor calls.

 It evident to me that the compiler must somehow
synthesise the destructor of a derived class using base
class and member destructors, but its not at all obvious
it actually has to call them.

 That is, its not apparent whether member and or
base class subobjects of a complete object are objects at all:
if they do not have constructors and destructors called for them,
the subobjects are not distinct from the complete object, and dont
come into existence until the complete object is fully
constructed.

 If, on the other hand actual constructors and destructors
of a member are called, then these members have lifespans
exceeding that of their containing object. And the question
arises at what stage their memory may be write protected,
if they happen to be const members.

 Of course base subobjects are special. They certainly
dont have the same properties as complete objects.
Probably, they're not objects at all.  Which means there
are pointers that dont point exactly at objects of
the type of the pointer. (Such pointers *usually* point
somewhere into an object of a type derived from the type
of the pointer .. except duing construction and destruction,
when the 'this' pointer is a charade)

 Markku Sakkinen invented the term 'difference subobjects'
which are the extra bits a derived class adds on to its bases.
These at least appear to occupy continuous store which base
class subobjects need not.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,      CSERVE:10236.1703
        6 MacKay St ASHFIELD,     Mem: SA IT/9/22,SC22/WG21
        NSW 2131, AUSTRALIA