[expr.static.cast] / P11:
The value of the class "pointer to cv1 B ", where B is the type of the class, can be converted to prvalue of the type "pointer to cv2 D ", where D is the class (section 10) from B if the standard conversion from "pointer to D " to "is valid a pointer to B exists (4.10), cv2 is the same cv-qualification as or a higher cv-qualification than cv1 and B is neither a virtual base class D , nor a base class virtual base class D The value of the null pointer (4.10) is converted to the null value of the pointer of the destination type. If the type value "pointer to cv1 B " points to B , which is actually a subobject of an object of type D , the resulting pointer points to an enclosing object of type D Otherwise, the behavior is undefined.
Thus, the question arises whether during static_cast pointer is actually "a B , which is actually a subobject of an object of type D ". If so, then there is no UB; if not, then undefined behavior means that the resulting pointer is dereferenced or otherwise used .
[class.dtor] / p15 says (my emphasis)
As soon as the destructor is called for the object, the object will no longer exist
and [basic.life] / p1 say that
The lifetime of an object of type T ends when:
- if T is a class type with a nontrivial destructor (12.4), the call to the destructor begins, or
- [...]
Thus, the lifetime of the object D ended as soon as its destructor was called, and, of course, by the time B destructor began to execute - which after the body of D finished executing the destructor. At this stage, there is no "object of type D " left, that this B can be a subobject - it "no longer exists." So you have UB.
Clang with UBsan will report an error in this code if B is made polymorphic (given the virtual function) that supports this reading.
source share