开发者

Null Pointer to Object problems

Hi can someone tell why in Linux and windows the same problem occurs :

#include <iostream>
using namespace std;

class A
{
private:
   int _dmember;

public:
   void func()
   {
     cout<<"Inside A!! "<<endl;
     cout<<_dmember; // crash when reach here.
   }
};

int main ()

{

    A* a= NULL;

    a->func(); // prints "Inside A!!!" 

    return 1;
}

can someone tell why this weird behivior occurs ? i mean , the a->func() was not supposed to get inside the func() ,...? this is unwated behavior ,

why the above behivor occurs?

EDIT: Of course , a* =null was intentionaly!! so for all who answered "this is 开发者_JAVA技巧undefined behavior" or "you should never try to call a function on a NULL pointer !!", come on.... that was the point. and this behavior was explained correctly by some of you.


This is undefined behaviour. You must never call functions on a null pointer.

With that out of the way, let's answer the question I think you're asking: why do we get partway into the function anyway?

When you are invoking UB, the compiler is free to do anything, so it's allowed to emit code that works anyway. That's what happens on some (many?) systems in this particular case.

The reason that you're able to call the function on a null pointer successfully is that your compilers don't store the function "in" the object. Rather, the above code is interpreted somewhat like this:

class A {
    int _dmember;
};

void A::func(A *this) {
    cout << "Inside A!!" << endl;
    cout << this->_dmember << endl;
}

int main() {
    A *a = ...;
    A::func(a);
}

So, you see there is nothing that actually prevents you from calling a function on a null pointer; it'll just invoke the body of the function, with the this pointer set to null. But as soon as the function tries to dereference the this pointer by accessing a field inside the class, the operating system steps in and kills your program for illegal memory access (called segmentation fault on Linux, access violation on Windows).

Nitpicker's corner: Virtual functions are a different story.


Undefined behavior because you are accessing a NULL pointer:

A* a= NULL;
a->func(); // is not defined by the language

Note that even if func() didn't try to access a member variable, the behavior still is undefined. For example, the following code could run without errors, but it is not correct:

   func()
   {
     cout<<"Inside A!! "<<endl;
   }

EDIT: With my full respect, C++ doesn't suck!

What you need is a smart pointer, not a raw pointer. As my professor says always, if you don't know what you are doing in C/C++, it is better not to do it!

Use boost::scoped_ptr, and enjoy exception safety, automatic memory management, zero overhead and NULL checking:

struct test
{
    int var;
    void fun()
    {
        std::cout << var;
    }
};

int main()
{
    boost::scoped_ptr<test> p(NULL);
    p->fun(); // Assertion will fail, Happy debugging :)
}


Dereferencing a null pointer is undefined behaviour. Everything could happen, so don't do it. You must check that the pointer is valid before dereferencig it. this pointer cannot be null so you wouldn't avoid the undefined behaviour.


Most compilers just pass the pointer to the class as the first parameter (The this pointer). If you don't go on to de-reference the this pointer then you are not actually going to cause a crash. Your this pointer, inside the functiom, will simply be NULL.

As AraK pointed out this is undefined behaviour so your mileage mat vary...


Aren't you supposed to allocate a memory for your pointer? I just wonder what is the intention to call a function of a NULL pointer? It's supposed to crash immediately. It doesn't crash on the line where you don't call to A member _dmember,but the moment you call it your function crashes cause the object is simply not allocated. _dmember points on undefined memory... That's why it crashes


Its a null pointer, you simply can't define what should happen if we call a function on it.


Any pointer variable is supposed to point to some object.

Your declaration A * a = NULL; does not point anywhere and so will not yield the results as it should.

You can however try this

A * a = NULL;
A b;
a=&b;
a->func();

this will yield the output.


Since there are no virtual functions in your class, it's easier here to think about what C code would be generated to represent this type. Approximately:

#include <stdio.h>


typedef struct
{
  int d_;
} A;


FILE* print_a_to(A* a, FILE* dest)
{
  return fprintf(dest, "Inside A!! \n") < 0 ||
         fprintf(dest, "%d", a->d_) < 0 ?
         NULL :
         dest;
}


int main(int argc, char* argv[])
{
  A* a = NULL;
  return NULL == print_a_to(a, stdout) ?
         -1 :
         0;
}

Look at the second line of function print_a_to; see the dereferencing of pointer a? Per the first line of function main, you're passing NULL as the value of pointer a. Dereferencing a null pointer here is equivalent to calling a member function on your class that needs access to its member variables through a null pointer.


if i was'nt clear, i am not trying to do deliberately below:

A* a=NULL;    
a->f(); 

i wrote that code just to check why is it working , and ofcourse i was disappointed and my reason to be disapointed is that i debug very big program in Redhat-Linux , through log-files concept( meaning - Printing Entering,Exiting from functions to logs, including printing imporant values). AND, on my way on the logs i hoped that if im on specific STACK of function calls i hoped at least the instances operating these functions are alive, but as i discovered and disapointed its not ought to be , which for me disapointement because it makes the debug through log files even more difficult.


I hope you described the symptoms exactly as what you saw. I tried on both Windows and Linux. Linux gives a segment fault, and Windows displays the error dialog.

The address area around 0x0 is protected by Windows and Linux. Reading and writing in this memory area will cause the OS throws an exception. Your application can catch the exception. Most application do not, and OS default handling routine is to print some error message and terminate the program.

One may ask why the message ""Inside A!! " is printed before termination. The answer is that at backend, C++ compiler converts class methods into procedure calls. This step does not involve pointer dereference. You can think that the result look like this:

void A_func(A* a)
{
     cout<<"Inside A!! "<<endl;
     cout<<a->_dmember; // crash when reach here.
}

A* a = NULL; A_func(a);

The dereference of NULL pointer happened at the second statement. So the first statement was executed just fine.


the point is that the -> operator on class object (with no vtable) is not a dereference of the pointer

a->foo()

is really shorthand for

A::foo(a)

where the first param gets transformed into the this pointer. Its when u try to deref 'this' by referring to member variable that things go bad.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜