“dynamic_cast”之后的 NULL 指针实际上可以被取消引用吗?
Posted
技术标签:
【中文标题】“dynamic_cast”之后的 NULL 指针实际上可以被取消引用吗?【英文标题】:Can NULL pointer after "dynamic_cast" actually be dereferenced? 【发布时间】: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”会导致程序崩溃。
感谢您的帮助。
【问题讨论】:
【参考方案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
【讨论】:
以上是关于“dynamic_cast”之后的 NULL 指针实际上可以被取消引用吗?的主要内容,如果未能解决你的问题,请参考以下文章
在没有dynamic_cast的大层次结构中确定基指针的真实类型