Why Does Calling Method Through Null Pointer "Work" in C++

Why does calling method through null pointer work in C++?

The pointer isn't needed to call the method. The type of the pointer is known, so the code for the method is known. The method doesn't use this, so it runs the code just fine. It's undefined behavior, but its more efficient not to check if the pointer is NULL, so it runs.

Why is it okay to call free with null pointer?

The malloc function (as well as calloc and realloc) may return a NULL pointer if the requested size is 0. Therefore, it makes sense that NULL pointer can also be passed to free since it was returned from a successful call to malloc:

Section 7.22.3p1 of the C standard specifies this behavior:

If the space cannot be allocated, a null pointer is returned. If the
size of the space requested is zero, the behavior is
implementation-defined: either a null pointer is returned, or the
behavior is as if the size were some nonzero value, except
that the returned pointer shall not be used to access an object.

Does calling a method on a NULL pointer which doesn't access any data ever fail?

Can you think of any plausible reason why any future compiler wouldn't behave as expected?

A helpful compiler might add code to access the real object under the hood in debug builds in the hope of helping you catch this issue in your code early in the development cycle.

What if the function does modify members, but the NULL ptr is guarded against. For instance,

void foo::blah()
{
foo* pThis = this ? this : new foo();
pThis->i++;
}

Since it is undefined behavior to call that function with a null pointer, the compiler can assume that the test will always pass and optimize that function to:

void foo::blah()
{
this->i++;
}

Note that this is correct, since if this is not null, it behaves as-if the original code was executed, and if this was null, it would be undefined behavior and the compiler does not need to provide any particular behavior at all.

Why calling function with nullPtr does not crash my application?

This is a common thing in C++, the function is not part of the instance, but part of the class definition.

If you tried to access this in the function then you would have a crash.

As @YSC mentioned below, this is considered undefined behavior, and you should not assume this will work. but it will mostly work and i heard this is even asked in C++ interviews questions.

Pointer this of a class turns into null when calling a method of that class C++

The assumption: "textures is not null pointer because i can access to "applyTexture" from there." is wrong. applyTexture is not a function pointer, it's a class method.

The compiler actually converts your object notation call into:

PAGTexture::applyTexture(textures, t + i, id_revol.at(i));

passing nullptr doesn't bother the compiler like at all. But when entering the method, this==nullptr and it crashes when you access a member.

It's different with data members (would probably have crashed at once), hence your confusion.

To play it safe, you could do things like:

void PAGTexture::loadTexture(char * path_img, GLuint min_filter, GLuint mag_filter)
{
assert(this!=nullptr);

that will crash with a failed assertion if method is called with a null pointer (note: only works if optimizations are turned off, else the compiler assumes that this cannot be nullptr when optimizing even with -O1)

Why would code explicitly call a static method via a null pointer?

Static member functions were added into C++ in 1989, in Release 2.0 of the AT&T C++ Language System (pre-standardisation). Prior to that, the static keyword could not be used to declare static member functions, so code authors used workarounds, principally the one you have observed of indirecting a null pointer.

In the Selected Readings accompanying version 2.0 of the AT&T C++ Language System, in section 1-22, Stroustrup writes:

It was also observed that nonportable code, such as:

((X*)0)->f();

was used to simulate static member functions. This trick is a time bomb because sooner or later someone will make an f() that is used this way virtual and the call will fail horribly because there is no X object at address zero. Even where f() is not virtual such calls will fail under some implementations of dynamic linking.

Your code was written to compile under Cfront 1.0 or by someone who was not aware at the time of the addition of static member functions to the language.

The annotation of the member function with static is indeed a puzzle, as Cheers and hth. - Alf has observed; Cfront 1.0 would have rejected that code with:

error:  member Method() cannot be static

so it cannot have been there initially. I think Potatoswatter is most likely correct; static was added at a later date to document and enforce the static method attribute of Method, once a C++ 2.0 compiler could be guaranteed to be available, but without the calling code being updated. To confirm this you'd need to interview the original programmer(s) or at least examine source control history (if any exists).

Calling class method through NULL class pointer

Under the hood most compilers will transform your class to something like this:

struct _ABC_data{  
int a ;
};
// table of member functions
void _ABC_print( _ABC_data* this );

where _ABC_data is a C-style struct
and your call ptr->print(); will be transformed to:

_ABC_print(nullptr)

which is alright while execution since you do not use this arg.


UPDATE: (Thanks to Windows programmer for right comment)

Such code is alright only for CPU which executes it.

There is absolutely positively no sane reason to exploit this implementation feature. Because:

  1. Standard states it yields undefined behavior
  2. If you actually need ability to call member function without instance, using static keyword gives you that with all the portability and compile-time checks

What will happen when I call a member function on a NULL object pointer?

It's undefined behavior, so anything might happen.

A possible result would be that it just prints "fun" since the method doesn't access any member variables of the object it is called on (the memory where the object supposedly lives doesn't need to be accessed, so access violations don't necessarily occur).



Related Topics



Leave a reply



Submit