Topic: Pure virtual call from a dtor
Author: jamshid@ses.com (Jamshid Afshar)
Date: 5 Apr 1994 10:35:04 -0500 Raw View
Redirected to comp.std.c++.
In article <pjl.765412961@graceland.att.com>,
Paul J. Lucas <pjl@graceland.att.com> wrote:
>In <NEERI.94Apr3235100@yggdrasil.ethz.ch> neeri@iis.ee.ethz.ch (Matthias Neeracher) writes:
>>>> class Test{
>>>> public:
>>>> virtual ~Test() { Pure(); } // should compiler give error?
>>>> virtual int Pure() = 0;
>>>> };
>>>
>>> The code is legal. I can find nothing forbidding it in the ARM;
>>> *con*structors are another matter.
>>
>>[...] it seems clear to me that it applies equally to destructors,
>
> There is no room for supposition. It either says it or it doesn't.
> Given that it is not expressly forbidden, it is allowed.
No, there is a lot of room for supposition and correction when reading
the ARM. A strict reading of the ARM or even Jan 1994 WP leads to
inconsistent or incomplete rules, so there's no point in being
pedantic, at least not until we get a draft, which is intended to
stand up to pedantic readings.
>>This behavior makes perfect sense: Once a virtual destructor is called, any
>>of the "derived objects" have already been destructed and thus their "class
>>invariants" no longer hold, which makes calling members defined there very
>>dangerous.
>
> While the poster's code has a virtual destructor, that's not the
> issue; the issue is whether a pure virtual *function* can be
> called from a destructor. Since objects are destroyed bottom
> up, the most-derived function *can* be called it seems.
> Obviously, this is not true for CONstruction since the most
> derived part hasn't been constructed yet.
> So perhaps the "omission" in the ARM is intentional.
Your description of destructors is wrong (I would say your
"understanding", but I know how you hate it when people assume more
than you write). The body of the most derived destructor is executed
first, then the derived object's members are destroyed, then the base
class dtor is called, after which the base class' members are
destroyed, etc. Whether you consider it bottom-up or top-down depends
on your orientation, but the order is well defined.
It is very analogous to construction because in either the constructor
or destructor, "the function called will be the one defined in the
constructor's (or destructor's) own class or its bases, but *not* any
function overriding it in a derived class. This ensures that
unconstructed objects will not be accessed during construction or
destruction" (ARM/WP 12.7).
I agree with Matthias that it's obviously an ommission in the ARM/WP
that the next paragraph in 12.7 ("the effect of calling a pure virtual
[...] is undefined") only mentions constructors (ditto for 10.3
Abstract Classes). Again, a rigorous answer to the question of
whether or not the code is "legal" is impossible since the question
cannot be rigorously answered by any existing standard document
(probably because there is no rigorous standard document yet). If you
want to be pedantic, then at least define "legal", taking note of the
WP's definition of the term "Undefined behavior".
IMO a good compiler will diagnose an error in the above code. There's
no way to call Test's definition of the virtual function Pure()
because there is no such function defined. Note, even in the case of
calling a pure virtual in a constructor the ARM and WP (at least for
now) simply describe the effect as "undefined behavior". This does
not *require* a compile-time diagnostic.
Jamshid Afshar
jamshid@ses.com