static_cast 向下转换实际上不是对象类型的类型是否是未定义的行为?

big*_*iao 3 c++ static-cast language-lawyer

这里是stackoverflow 上对四种显式强制转换的讨论。但我在得票最多的答案中遇到了一个问题。

引用来自得票最多的 wiki 答案:

static_cast也可以通过继承层次结构进行转换。当向上转换(朝向基类)时,它是不必要的,但是当向下转换时,只要它不通过 virtual继承进行转换,就可以使用它。但是,它不进行检查,并且将层次结构下降到实际上不是对象类型的类型是未定义的行为static_cast

但在cppref中,我读到了一些不那么严重的内容:
static_cast < new_type > ( expression )

如果 new_type 是某个类 D 的指针或引用,并且表达式的类型是对其非虚拟基 B 的指针或引用,则static_cast执行向下转型。如果 B 是不明确的、不可访问的或 D 的虚拟基(或虚拟基的基),则这种static_cast 向下转型是错误的。这样不会进行运行时检查来确保对象的运行时类型实际上是 D,并且只能安全地使用如果这个前提可以通过其他方式来保证。

因此,在 cppref 中,它并没有说未定义的行为,而是说不那么严重,因为不安全

所以当我做类似的事情时:

class A{virtual foo(){}};
class B:public A{};
class C:public B{};
int main()
{
  C*pc=new C;
  A*pa=static_cast<A*>(pc);//Ok,upcast.
  B*pb=static_cast<B*>(pa);//downcast,**is it undefined or just not safe?**
  C* pc1=static_cast<C*>(pb);//downcast back to C;
}
Run Code Online (Sandbox Code Playgroud)

还有一个问题,如果不是UB,解引用也是UB吗pb

Bar*_*rry 7

cppreference 用英文编写,旨在传达良好的理解,它实际上不是规范。但我对这里的措辞没有问题:

\n\n
\n

这样static_cast不会进行运行时检查来确保对象的运行时类型实际上是 D,并且只有在通过其他方式保证此前提条件时才可以安全使用。

\n
\n\n

如果你保证了前提,那就没问题了。如果您不能保证前提条件,那么您的代码就不安全。代码不安全意味着什么?其行为未定义。

\n\n

实际规范使用这样的措辞

\n\n
\n

如果 \xe2\x80\x9c 类型的纯右值指向cv 1 B \xe2\x80\x9d 指向的 aB实际上是 类型对象的子对象D,则生成的指针指向类型的封闭对象D。否则,行为是未定义的。

\n
\n\n
\n\n

无论哪种方式,在您的示例中,您的所有转换都是有效的。

\n\n
B*pb=static_cast<B*>(pa);//downcast,**is it undefined or just not safe?**\n
Run Code Online (Sandbox Code Playgroud)\n\n

你缺少这个条件。沮丧本身并不是未定义的行为。如果那里实际上不存在派生类型的对象,则这只是未定义的行为。在本例中pa, 指向 a C,它是 a B,因此对 a 的强制转换B是安全的。

\n\n

然而,这不是:

\n\n
struct B { };\nstruct D1 : B { };\nstruct D2 : B { };\n\nB* p = new D1;\nstatic_cast<D2*>(p); // undefined behavior, no D2 object here\n
Run Code Online (Sandbox Code Playgroud)\n