That is, is something like this always legal?
struct Derived;
struct Base { Base(Derived*); };
struct Derived : Base { Derived() : Base(this) { } };
Base::Base(Derived *self) {
if(static_cast<Base*>(self) != this) std::terminate();
}
int main() {
Derived d; // is this well-defined to never call terminate?
}
At the point that the static_cast
is evaluated, self
does not yet point to a Derived
object—that object is under construction. E.g. if Derived
had data members, their constructors would not have been called. Is the cast still guaranteed to be defined behavior, resulting in a pointer equivalent to Base
's this
(which does point to a fully constructed Base
base class subobject)?
A standard quote that I think gets close to answering this is [conv.ptr]/3
.
...The result of the conversion is a pointer to the base class subobject of the derived class object. ...
But I think there is no derived class object yet, so what happens? If it is indeed undefined, does the answer change for self != static_cast<Derived*>(this)
?
(Clang and GCC compile and run this "as expected".)