我偶然发现了这段对我来说似乎完全被破坏的代码,但它确实发生this
了null
。我只是不明白这怎么可能null
它在正常的方法调用中,例如
myObject->func();
在里面MyObject::func()
我们有
if (!this) { return false; }
有什么办法可以让第一行抛出 aNullPointerException
而不是进入null
(?) 方法?
如果你有:
MyObject *o = NULL;
o->func();
接下来会发生什么取决于是否func
是虚拟的。如果是,那么它将崩溃,因为它需要一个对象来从中获取 vtable。但如果它不是虚拟的,则调用会继续将 this 指针设置为 NULL。
我相信标准说这是“未定义的行为”,所以任何事情都可能发生,但典型的编译器只是生成代码而不检查指针是否为 NULL。一些著名的库依赖于我描述的行为:MFC 有一个函数,叫做类似的函数SafeGetHandle
,可以在空指针上调用,在这种情况下返回 NULL。
您可能想编写一个可重用的辅助函数:
void CheckNotNull(void *p)
{
if (p == NULL)
throw NullPointerException();
}
然后,您可以在函数的开头使用它来检查其所有参数,包括this
:
CheckNotNull(this);
捕获此类错误的一种方法(通过设计)是使用指针包装类(类似于 a shared_ptr
),该类在创建时使用空指针参数抛出。取消引用时它也可能抛出,但这有点晚了 - 我猜总比没有好。
if(this == null)
throw new NullPointerException;
if(!this)
return false;
有可能为this
空。我怀疑此代码正试图(严重)检测竞争条件,其中对象尚未完成初始化或已被删除。
(this == NULL) 根据标准是未定义的行为。我认为您应该删除此检查:)
假设我们进行以下调用:
((CSomeClass*) 0)->method();
行为已经未定义,那么为什么还要在 CSomeClass::method 中检查 this == NULL 呢?
已编辑: 我假设如果您不使用成员变量,您的编译器将处理 (0 == this),但它会在哪里找到虚拟表指针?在这种情况下,您的班级不能使用多态性。
在以下情况下,此指针可能变为空:
class Test
{
public:
bool f();
private:
int m_i;
};
bool Test::f()
{
if(!this)
{
return false;
}
m_i = 0;
return true;
}
int main(int argc, char **argv)
{
Test* p = new Test;
delete p;
p = NULL;
p->f();
}
我猜有人做了一个快速破解来避免访问冲突异常。
this == null 仅当您在已删除对象上调用方法时才会发生,或者如果某些内容正在写入不应写入的内存(特别是覆盖对象的 this 指针)。
您应该调查代码的真正问题,而不是像这样尝试解决它。