This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


2839. Explicit destruction of base classes

Section: 11.4.7  [class.dtor]     Status: open     Submitter: Jiang An     Date: 2023-12-07

(From submission #478.)

Consider:

  struct B {};
  struct D1 : virtual B {};
  struct D2 : virtual B {};
  struct D : D1, D2 {};

  void f() {
    D *d = new D;
    static_cast<D2&>(*d).~D2();
  }

According to 11.4.7 [class.dtor] paragraph 13, invoking a destructor for a most derived object is different from invoking it for a base class subobject:

After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members, the destructors for X's non-virtual direct base classes and, if X is the most derived class (11.9.3 [class.base.init]), its destructor calls the destructors for X's virtual base classes.

However, there is no means to convey the difference in an explicit destructor call. As an aside, potentially-overlapping subobjects cannot be transparently replaced, thus any attempt at replacement would implicitly end the lifetime of the complete object due to storage reuse.

Possible resolution:

Split 7.6.1.3 [expr.call] paragraph 4 and amend, as follows:

..., even if the type of the function actually called is different.

If the postfix-expression P names a destructor or a pseudo-destructor, the postfix-expression is a possibly-parenthesized class member access. If P names a destructor, the behavior is undefined if the object expression denotes a base class subobject and that base class is or has a virtual base class or a virtual function (11.4.7 [class.dtor]). If the postfix-expression P names a pseudo-destructor (in which case the postfix-expression is a possibly-parenthesized class member access), the function call destroys the object of scalar type denoted by the object expression of the class member access (7.6.1.5 [expr.ref], 6.7.3 [basic.life]).