2014-03-07 81 views
2

我想知道为什么下面的小程序不会导致NullPointerException。 任何想法? 输出是2x Hello World !!!在我的MacBook上使用clang-500.2.79。空指针可访问

#include <iostream> 

using namespace std; 

class Strange { 
public: 
    Strange() {} 
    virtual ~Strange() {} 
    void sayHello() { 
     cout<<endl<<"Hello World!!!"<<endl; 
    } 

}; 

int main(void) { 
    Strange* s = new Strange(); 
    delete s; s = NULL; 
    s->sayHello(); 
    (*s).sayHello(); 
    return 0; 
} 

回答

2

我想知道为什么下面的小程序不会导致NullPointerException。

因为它是C++,而不是一种“托管”语言,每次操作都需要昂贵的运行时检查。如果您取消引用空指针,则不会发生异常;你会得到某种未定义的行为。

在这种情况下,成员函数不访问对象,因此(在大多数实现中)它的行为就像指针是有效的一样。如果它确实访问了该对象,那么您可能会遇到运行时错误或内存损坏,从而导致微妙的错误和不眠之夜。

避免指针和new当你可以;必要时使用智能指针和其他RAII技术。如果指针可能为空,那么在解引用它之前检查它。

+0

不完全正确......我期望对NULL解引用有一个分段错误。不过,我认为编译器优化只是忽略了解引用操作,因为该函数不使用'this'参数,所以不会发生实际的解除引用。 – immortal

+0

@immortal:只有当内存被访问时,并且只有当指针指向一个不可访问的内存页面时,并且只有当硬件支持内存保护时。分段故障是一个硬件级别的故障,它只是由实际访问内存的尝试触发的;它对解引用等软件级概念一无所知。 –

+0

我尝试了几个编译器优化,现在也尝试了最新的gcc(从-O0直到O3),输出始终工作,我从来没有得到任何seg故障或其他异常:( – Mats

8

C++没有“NullPointerException”。解引用空指针就是Undefined Behavior,任何事情都可能发生。

在你的情况,sayHello()不访问*this可言,所以它发生在工作“正常”(你的编译器,优化设置,运行时间& HW)。但这并不能保证。未定义的行为只是未定义的;该程序可能会崩溃或在网上订购披萨。

+0

谢谢你的回答。所以在将指针设置为NULL之后我有未定义的行为。如果我不会将指针设置为NULL,那么我有一个悬挂指针,对吧?这也有一些不确定的行为,可能会更糟......所以我怎样才能避免这种不确定的行为? – Mats

+0

@ user3392371将指针设置为空不是UB。 *解引用*这样的指针是UB(如引用一个单位化的或更多的悬空指针)。解决方案取决于你的情况:如果指针可以为null,则在使用之前测试它:'if(s)s-> sayHello();'。如果指针非空是你的代码的前提条件,那么将它作为一个相应的调用来记录它(即确保指针真的不为空)。在这种情况下,你也可以'assert()'它不是null,这会让你在调试版本中进行错误检查。 – Angew