NULL指针与static_cast的兼容性

Gay*_*yan 5 c++ casting

Q1.为什么使用带有static_cast的NULL指针会导致崩溃,而dynamic_cast和reinterpret_cast会返回一个NULL指针?

问题发生在类似于下面给出的方法中:

void A::SetEntity(B* pEntity, int iMyEntityType)
{   
    switch (iMyEntityType)
    {   
    case ENTITY1:
        {
            Set1(static_cast<C*>(pEntity));
            return;
        }
    case ENTITY2:
        {
            Set2(static_cast<D*>(pEntity));
            return;
        }
    case ENTITY3:
        {
            Set3(static_cast<E*>(pEntity));
            return;
        }   
    }
}

Inheritance:
  class X: public B
  class Y: public B
  class Z: public B

  class C: public X, public M
  class D: public Y, public M
  class E: public Z, public M
Run Code Online (Sandbox Code Playgroud)

Q2.从B到C/D/E的static_casting是否有效?(这个工作正常,直到输入变为NULL)

我正在使用gcc 3.4.3版

sha*_*oth 8

你可以static_cast使用空指针 - 它会给你一个空指针.

在你的片段中的问题是最有可能的是你传递的不一致的值pEntity,并iMyEntityType到函数.因此,当static_cast它完成时,它会盲目地转换为错误的类型(与实际对象的类型不同),并且您得到一个无效的指针,该指针稍后会传递给调用堆栈并导致未定义的行为(崩溃程序).dynamic_cast在相同的情况下,看到该对象实际上不是预期的类型,并返回一个空指针.


Mic*_*urr 4

你使用什么编译器?从基类型到派生类型的静态转换可能会导致对指针的调整 - 特别是在涉及多重继承的情况下(从您的描述来看,这似乎不是您的情况)。然而,即使没有 MI,这仍然是可能的。

\n\n

该标准表明,如果对空指针值进行强制转换,则结果将是空指针值(5.2.9/8 静态强制转换)。但是,我认为在许多编译器上,大多数向下转型(特别是涉及单继承时)不会导致指针调整,因此我可以想象编译器可能存在错误,因此不会进行特殊检查对于 null 来说,需要避免将零值空指针“转换”为某些非零值无意义指针。我认为,对于存在这样的错误,您必须执行一些不寻常的操作,以使编译器必须调整向下转换中的指针。

\n\n

查看为您的示例生成了哪种汇编代码可能会很有趣。

\n\n

有关编译器如何布局可能需要使用静态转换进行指针调整的对象的详细信息,Stan Lippman 的“C++ 对象模型内部”是一个很好的资源。

\n\n

Stroustrup 关于 C++ 多重继承的论文(1989 年)也值得一读。如果 C++ 编译器存在像我推测的那样的错误,那就太糟糕了 - Stroustrup 在那篇论文(4.5 零值指针)中明确讨论了空指针问题。

\n\n

对于你的第二个问题:

\n\n
\n

Q2。从 B 到 C/D/E 的 static_casting 有效吗?

\n
\n\n

只要当您执行 B 指针到 C/D/E 指针的转换时,B 指针实际上分别指向 C/D/E 对象的 B 子对象,并且 B 不是,这就是完全有效的。虚拟基地。标准的同一段落中提到了这一点(5.2.9/8 静态投射)。我突出显示了与您的问题最相关的段落中的句子:

\n\n
\n

\xe2\x80\x9c 类型的右值指向 cv1 B\xe2\x80\x9d,其中 B 是类类型,可以转换为 \xe2\x80\x9c 类型的右值指向 cv2 D\xe2\x80\x9d ,其中 D 是从 B 派生的类(第 10 条),如果存在从 \xe2\x80\x9cpointer 到 D\xe2\x80\x9d 到 \xe2\x80\x9cpointer 到 B\xe2\x80\x9d 的有效标准转换(4.10),cv2 与 cv1 的 cv 限定相同或更高,并且 B 不是 D 的虚拟基类。 空指针值 (4.10) 转换为目标的空指针值类型。如果类型 \xe2\x80\x9c 指向 cv1 B\xe2\x80\x9d 的指针的右值指向实际上是 D 类型对象的子对象的 B,则生成的指针指向 D 类型的封闭对象。否则,转换的结果是未定义的。

\n
\n\n

最后,您可以使用以下方法解决该问题:

\n\n
Set1(pEntity ? static_cast<C*>(pEntity) : 0);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是编译器应该为你做的事情。

\n