NULL 指针与 static_cast 的兼容性

新手上路,请多包涵

Q1。为什么将 NULL 指针与 static_cast 一起使用会导致崩溃,而 dynamic_castreinterpret_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

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

我正在使用 gcc 版本 3.4.3

原文由 Gayan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 835
2 个回答

你用的是什么编译器?从基类型到派生类型的静态转换可能会导致对指针的调整 - 特别是在涉及多重继承的情况下(根据您的描述,情况似乎并非如此)。但是,如果没有 MI,它仍然是可能的。

该标准表明,如果正在转换空指针值,则结果将是空指针值(5.2.98 静态转换)。但是,我认为在许多编译器上,大多数向下转换(尤其是在涉及单继承时)不会导致指针调整,所以我可以想象编译器可能有一个错误,它不会对 null 进行特殊检查这将需要避免将零值空指针“转换”为一些非零值无意义的指针。我假设要存在这样的错误,您必须做一些不寻常的事情来让编译器不得不调整向下转换中的指针。

看看为您的示例生成了什么样的汇编代码可能会很有趣。

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

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

对于你的第二个问题:

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

这是完全有效的,只要当您将 B 指针转换为 C/D/E 指针时,B 指针实际上指向 C/D/E 对象的 B 子对象(分别)并且 B 不是不是虚拟基地。这在标准的同一段落(5.2.98 Static cast)中有所提及。我强调了与您的问题最相关的段落中的句子:

“指向 cv1 B 的指针”类型的右值,其中 B 是类类型,可以转换为“指向 cv2 D 的指针”类型的右值,其中 D 是从 B 派生的类(第 10 条),如果一个有效的标准存在从“指向 D 的指针”到“指向 B 的指针”的转换 (4.10),cv2 与 cv1 具有相同的 cv 限定或大于 cv1 的 cv 限定,并且 B 不是 D 的虚拟基类。空指针value (4.10) 被转换为目标类型的空指针值。如果“指向 cv1 B 的指针”类型的右值指向实际上是 D 类型对象的子对象的 B,则生成的指针指向 D 类型的封闭对象。 否则,强制转换的结果是未定义的.

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

 Set1(pEntity ? static_cast<C*>(pEntity) : 0);

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

原文由 Michael Burr 发布,翻译遵循 CC BY-SA 2.5 许可协议

你可以 static_cast 一个空指针——它会给你一个空指针。

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

原文由 sharptooth 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题