Title
Polymorphic behavior during destruction
Status
drafting
Section
11.4.7 [class.dtor]
Submitter
Richard Smith

Created on 2015-07-13.00:00:00 last changed 115 months ago

Messages

Date: 2015-07-13.00:00:00

Consider the following example:

  #include <stdio.h>
  struct Base {
    Base *p;
    virtual void f() { puts("base"); }
    ~Base() {
      p->f();
    }
  };
  struct Derived : Base {
    Derived() { p = this; }
    void f() { puts("derived"); }
    void g() {
      p->f();
      delete this;
    }
  };
  void h() {
    Derived *p = new Derived;
    p->g();
  }

Should this have defined behavior? On the one hand, the Derived object is in its period of destruction, so the behavior of the p->f() call in the Base destructor should be to call Base::f(). On the other hand, p is a pointer to a Derived object whose lifetime has ended, and the rules in 6.7.4 [basic.life] don't appear to allow the call. (Calling this->f() from the Base destructor would be OK — the question is whether you can do that for a pointer that used to point to the derived object, or if you can only do it for a pointer that was “created” after the dynamic type of the object changed to be Base.)

If the above is valid, it has severe implications for devirtualization. The purpose of 6.7.4 [basic.life] paragraph 7 appears to be to allow an implementation to assume that if it will perform two loads of a constant field (for instance, a const member, the implicit pointer for a reference member, or a vptr), and the two loads are performed on the “same pointer value”, then they load the same value.

Should there be a rule for destructors similar to that of 11.4.5 [class.ctor] paragraph 12?

During the construction of a const object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor's this pointer, the value of the object or subobject thus obtained is unspecified.
History
Date User Action Args
2015-07-13 00:00:00admincreate