2

I am wondering why the following little program does not cause a NullPointerException. Any ideas? The output is 2x Hello World!!! on my macbook using 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;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Mats
  • 23
  • 2

2 Answers2

8

C++ doesn't have a "NullPointerException." Dereferencing a null pointer is simply Undefined Behaviour and anything can happen.

In your case, sayHello() does not access *this at all, so it happens to work "normally" (on your compiler, optimisation settings, runtime & HW). But that's not guaranteed. Undefined behaviour is simply undefined; the program could just as well crash or order pizza online.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thank you for you answer. So I have undefined behavior after setting a pointer to NULL. If I would not set the pointer to NULL I have a dangling pointer, right? Which has also some kind of undefined behavior and could be even worse... So how can I avoid such kind of undefined behaviors? – Mats Mar 07 '14 at 11:46
  • @user3392371 Setting a pointer to null is not UB. *Dereferencing* such a pointer is UB (as is dereferencing an unitilialised or othwerwise dangling pointer). Solution depends on your situation: if the pointer can be null, test it before using: `if (s) s->sayHello();`. If the pointer being non-null is a precondition of your code, document it as such an call it accordingly (i.e. make sure the pointer is actuallt not null). In such case, you can also `assert()` that it's not null, which will give you error-checking in debug builds. – Angew is no longer proud of SO Mar 07 '14 at 11:54
2

I am wondering why the following little program does not cause a NullPointerException.

Because it's C++, not a "managed" language with expensive run-time checks on every operation. You won't get an exception if you dereference a null pointer; you'll get some kind of undefined behaviour.

In this case, the member function doesn't access the object so (on most implementations) it will behave as if the pointer were valid. If it did access the object, then you might get a run-time fault, or memory corruption leading to subtle bugs and sleepless nights.

Avoid pointers and new when you can; use smart pointers and other RAII techniques when you must. If there's any chance that a pointer might be null, then check it before dereferencing it.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Not quite true... I'd expect a segmentation fault for NULL dereference. I do think, however, that a compiler optimization simply disregards the dereference operation since the function does not use the `this` argument, so no actual dereference occurs. – immortal Mar 07 '14 at 11:35
  • @immortal: Only if the memory is accessed, and only if the pointer points to an inaccessible memory page, and only if the hardware supports memory protection. A segmentation fault is a hardware-level fault which is only triggered by an actual attempt to access memory; it knows nothing of software-level concepts like dereferencing. – Mike Seymour Mar 07 '14 at 11:38
  • I tried a couple of compiler optimizations and also tried the latest gcc now (from -O0 until O3) and the output was always working and I never got any seg fault or other exception :( – Mats Mar 07 '14 at 11:51
  • @user3392371: Indeed; you'll only get a segfault if you actually try to access memory through the pointer, which your code doesn't do regardless of optimisation level. It simply passes the null pointer as to the function as `this`, then ignores it. If you make the function `virtual`, or add a member variable and read or write that in the function, then you'll probably get a fault. Better still: avoid undefined behaviour in the first place. – Mike Seymour Mar 07 '14 at 11:52
  • Thanks for your explenation! So the reason why it is working is that the member function is not accessing the object. With this information I can go on playing around... Big Thx!!! – Mats Mar 07 '14 at 12:19