【问题标题】:Can NULL pointer after "dynamic_cast" actually be dereferenced?“dynamic_cast”之后的 NULL 指针实际上可以被取消引用吗?
【发布时间】:2011-06-06 06:48:09
【问题描述】:

以下代码正确编译并得到神秘输出:

特殊的投资功能 00000000

(环境:C++ VS2010)

#include <iostream>
#include <vector>
using namespace std;

class Security {
public:
  virtual ~Security() {}
};

class Stock : public Security {};

class Investment : public Security {
public:
  void special() {
    cout << "special Investment function" << endl;
  }
};

int main() {
  Security* p = new Stock;
  dynamic_cast<Investment*>(p)->special();
  cout << dynamic_cast<Investment*>(p) << endl;
  return 0;
}

怎么可能?取消引用 NULL 指针并获得“正确”输出而不是崩溃? 是不是VS2010的特殊“特性”?

现在我明白了。我做了一个测试,似乎在“特殊”函数中取消引用“this”会导致程序崩溃。

感谢您的帮助。

【问题讨论】:

    标签: c++ visual-studio-2010 visual-c++


    【解决方案1】:

    取消引用空指针是未定义的行为 - 您可能会得到意想不到的结果。见this very similar question

    在这种情况下Investment::special()是以非虚拟方式调用的,所以你可以认为编译器只是创建了一个全局函数

    Investment_special_impl( Investment* this )
    

    并调用它传递一个空的this指针作为隐式参数。

    你不应该依赖这个。

    【讨论】:

      【解决方案2】:

      这是“未定义的行为”。将方法视为具有隐式参数,带有“this”。在您的情况下,NULL 作为“this”的实际参数传递。由于您没有引用“this”(隐式或显式)引用的任何对象数据,因此它没有崩溃。

      如果方法是虚拟的,它很可能会崩溃,因为虚拟调用通常是通过与对象关联的查找表(因此是“this”)调度的。

      由于编译器编写者可以随意实现“this”和虚拟成员查找表,因此您不应依赖这种行为。它是未定义的。

      【讨论】:

      • 是的,我在VS2010中测试过,如果函数是虚拟的,程序就会崩溃。
      【解决方案3】:

      在 C++ 的大多数实现中,非虚拟方法不需要调用有效的实例(不检查 this 会更快,因为标准不需要它)。

      您可以将指针设置为 NULL,如果您不访问实例字段,方法仍然会成功。

      虚拟方法需要有效的vtable,因此它们总是取消引用对象并在未初始化的情况下导致错误。

      【讨论】:

        【解决方案4】:

        你没有在这里取消引用空指针:你只需调用函数 Investment::special(NULL),它是非虚拟的,并且在它的主体中不会取消引用 this。尽管规范可能告诉这是未定义的行为,但编译器完全理智地不要在此处放置任何取消引用,这样程序就不会崩溃。

        【讨论】:

        • 我认为这大约是正确的 50%。从技术上讲,Turner 正在解引用空指针,因为 dynamic_cast 是非法的,它将指针变为空指针。对空指针的 this 调用仍然是非法的,无论它是否是虚拟的。然而,碰巧成员函数根本不使用任何类数据,所以它不会偶然崩溃(而且,编译器也可能优化了 this-call out)。
        【解决方案5】:

        取消引用 any NULL 指针是未定义的行为。

        【讨论】:

          【解决方案6】:

          您不应该取消引用 NULL 指针,因为它可能导致未定义行为。为什么您的代码有效是因为在方法中:

          void special() {
            cout << "special Investment function" << endl;
          }
          

          你真的没有提到this。为了演示它,只需在 Investment 类中声明一个变量并尝试在 special() 中打印它。你会遇到崩溃。

          【讨论】:

            【解决方案7】:

            取消引用空指针会调用未定义的行为,无论您如何获得空指针,无论是由于dynamic_cast 还是其他原因。

            【讨论】:

              【解决方案8】:

              我不确定取消引用 NULL 的问题,但我可以解释代码的行为。

              dynamic_cast(p)->special();

              打印:“特殊投资功能”

              cout (p)

              prints: "0xABABABA"

              就像跑步:

              cout

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-07-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-10-05
                • 2011-02-13
                • 1970-01-01
                相关资源
                最近更新 更多