This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-12-19
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.