Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing class members on a NULL pointer

I was experimenting with C++ and found the below code as very strange.

class Foo{ public:     virtual void say_virtual_hi(){         std::cout << "Virtual Hi";     }      void say_hi()     {         std::cout << "Hi";     } };  int main(int argc, char** argv) {     Foo* foo = 0;     foo->say_hi(); // works well     foo->say_virtual_hi(); // will crash the app     return 0; } 

I know that the virtual method call crashes because it requires a vtable lookup and can only work with valid objects.

I have the following questions

  1. How does the non virtual method say_hi work on a NULL pointer?
  2. Where does the object foo get allocated?

Any thoughts?

like image 627
Navaneeth K N Avatar asked Mar 21 '09 18:03

Navaneeth K N


People also ask

How do I access null pointer?

Declare a pointer p of the integer datatype. Initialize *p= NULL. Print “The value of pointer is”. Print the value of the pointer p.

What happens if you access a null pointer?

Because a null pointer does not point to a meaningful object, an attempt to dereference (i.e., access the data stored at that memory location) a null pointer usually (but not always) causes a run-time error or immediate program crash.

What happens when you access a null pointer in C++?

But by convention, if a pointer contains the null (zero) value, it is assumed to point to nothing. Thus, if all unused pointers are given the null value and you avoid the use of a null pointer, you can avoid the accidental misuse of an uninitialized pointer.

What happens if you call a null function pointer?

Initializing a pointer to a function, or a pointer in general to NULL helps some developers to make sure their pointer is uninitialized and not equal to a random value, thereby preventing them of dereferencing it by accident.


1 Answers

The object foo is a local variable with type Foo*. That variable likely gets allocated on the stack for the main function, just like any other local variable. But the value stored in foo is a null pointer. It doesn't point anywhere. There is no instance of type Foo represented anywhere.

To call a virtual function, the caller needs to know which object the function is being called on. That's because the object itself is what tells which function should really be called. (That's frequently implemented by giving the object a pointer to a vtable, a list of function-pointers, and the caller just knows it's supposed to call the first function on the list, without knowing in advance where that pointer points.)

But to call a non-virtual function, the caller doesn't need to know all that. The compiler knows exactly which function will get called, so it can generate a CALL machine-code instruction to go directly to the desired function. It simply passes a pointer to the object the function was called on as a hidden parameter to the function. In other words, the compiler translates your function call into this:

void Foo_say_hi(Foo* this);  Foo_say_hi(foo); 

Now, since the implementation of that function never makes reference to any members of the object pointed to by its this argument, you effectively dodge the bullet of dereferencing a null pointer because you never dereference one.

Formally, calling any function — even a non-virtual one — on a null pointer is undefined behavior. One of the allowed results of undefined behavior is that your code appears to run exactly as you intended. You shouldn't rely on that, although you will sometimes find libraries from your compiler vendor that do rely on that. But the compiler vendor has the advantage of being able to add further definition to what would otherwise be undefined behavior. Don't do it yourself.

like image 124
Rob Kennedy Avatar answered Oct 14 '22 04:10

Rob Kennedy