【发布时间】:2021-08-07 01:57:56
【问题描述】:
也就是说,这样的事情总是合法的吗?
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 基类子对象)?
我认为接近回答这个问题的标准引用是[conv.ptr]/3。
...转换的结果是指向派生类对象的基类子对象的指针。 ...
但我认为还没有派生类对象,那么会发生什么?如果确实未定义,self != static_cast<Derived*>(this) 的答案是否会改变?
(Clang 和 GCC “按预期”编译和运行它。)
【问题讨论】:
-
有 2 个子问题:自我保证等于这个,并且取消引用
static_cast<Base*>(self)是明确定义的。 -
在评估
static_cast时,self还没有指向Derived对象 为什么?那么self指向哪里呢? -
@LanguageLawyer 它指向未初始化的存储,
Derived对象最终将开始其生命周期,不是吗?我的报价是否有可能适用于不在其生命周期内的对象? -
指向未初始化的存储 timsong-cpp.github.io/cppwp/n4868/basic.compound#3.sentence-8 是什么意思? 我的引用是否有可能适用于不在其生命周期内的对象?很遗憾,不能,因为timsong-cpp.github.io/cppwp/n4868/basic.life#6.4
-
@LanguageLawyer 也许我最好将其改写为“指针指向不在其生命周期内的对象”。我猜该标准并没有真正定义对象“存在”的含义。另外,我不确定该段的限制是否完全适用:它说对于正在构建的对象的情况,您可以转到此处答案中引用的子条款(“否则”)。或者你说它仍然适用?那么
Base *ptr = self; if(self != this) std::terminate();是正确的而问题中的代码不是吗?
标签: c++ language-lawyer