将指向部分构造的对象的指针转换为指向基 class 的指针是否合法?
Is it legal to cast a pointer to a partially constructed object to a pointer to a base class?
也就是说,这样的事情总是合法的吗?
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?
}
在计算 static_cast
时,self
尚未指向 Derived
对象——该对象正在构建中。例如。如果 Derived
有数据成员,它们的构造函数就不会被调用。转换是否仍然保证定义为行为,导致指针等同于 Base
的 this
(确实指向完全构造的 Base
基础 class 子对象)?
我认为接近回答这个问题的标准引述是 [conv.ptr]/3
。
...The result of the conversion is a pointer to the base class subobject of the derived class object. ...
但我认为 还没有派生 class 对象,所以会发生什么?如果确实未定义,self != static_cast<Derived*>(this)
的答案会改变吗?
(Clang 和 GCC 编译并且 运行 这“符合预期”。)
这很好:[class.cdtor]/3
说
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X
to a pointer (reference) to a direct or indirect base class B
of X
, the construction of X
and the construction of all of its direct or indirect bases that directly or indirectly derive from B
shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. ...
它要求源类型(以及从目标类型继承的任何其他基类)开始它的构造函数并且没有完成它的析构函数。即使是基类的初始值设定项也算作派生构造函数的开始;该标准包含一个非常相似的示例。
也就是说,这样的事情总是合法的吗?
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?
}
在计算 static_cast
时,self
尚未指向 Derived
对象——该对象正在构建中。例如。如果 Derived
有数据成员,它们的构造函数就不会被调用。转换是否仍然保证定义为行为,导致指针等同于 Base
的 this
(确实指向完全构造的 Base
基础 class 子对象)?
我认为接近回答这个问题的标准引述是 [conv.ptr]/3
。
...The result of the conversion is a pointer to the base class subobject of the derived class object. ...
但我认为 还没有派生 class 对象,所以会发生什么?如果确实未定义,self != static_cast<Derived*>(this)
的答案会改变吗?
(Clang 和 GCC 编译并且 运行 这“符合预期”。)
这很好:[class.cdtor]/3
说
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class
X
to a pointer (reference) to a direct or indirect base classB
ofX
, the construction ofX
and the construction of all of its direct or indirect bases that directly or indirectly derive fromB
shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. ...
它要求源类型(以及从目标类型继承的任何其他基类)开始它的构造函数并且没有完成它的析构函数。即使是基类的初始值设定项也算作派生构造函数的开始;该标准包含一个非常相似的示例。