0
#include <iostream>

class Test {
public:
    int i;
    void print()
    {
        std::cout << "Hello" << std::endl;
    }
};

int main()
{
    class Test *p = NULL;
    p->print();
    (*p).print();
}

Output:

Hello
Hello

I understand that objects methods and members variables are stored in different location in memory but when p is assigned as NULL how it can resolve to invoke Test::print()

Test6:~ 1001> g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Test6:~ 1002> g++ manoj.cpp
Test6:~ 1003> ./a.out
Hello
Hello
Test6:~ 1004> cat manoj.cpp
#include <iostream>

class Test {
public:
int i;
void print()
{
std::cout << "Hello" << std::endl;
}
};

int main()
{
class Test *p = NULL;
p->print();
(*p).print();
}
Test6:~ 1005>
wattostudios
  • 8,666
  • 13
  • 43
  • 57
Sanjay
  • 7
  • 1

3 Answers3

3

Unless a class has virtual functions(i.e. compiler does not create vtable), all the pointers to the methods will be hardcoded in the program, thus not requiring any of the variable information. However, even in that case, it would not have a valid this pointer, so it will still crash.

JosephH
  • 8,465
  • 4
  • 34
  • 62
  • just like call a function `void print(class Test*)`. though the arg `class Test*` is not initialized, it still can work because the function content did not relate to the arg. – dongjk Nov 17 '11 at 05:37
0

You simply cannot do this. This code wouldn't compile, and you cannot address a null pointer. Try using:

int main()
{
    // no need for 'class' keyword when declaring the pointer:
    Test* p = new Test(); // use default constructor provided by compiler
    p->print();
    (*p).print();
    // you also need to delete the pointer before returning, but that's irrelevant
    return 0; // you need this too
}
Zeenobit
  • 4,954
  • 3
  • 34
  • 46
  • @SethCarnegie, No `return` from `main()` and the `class` keyword inside `main()`. You're making me doubt my C++ knowledge. :P – Zeenobit Nov 17 '11 at 05:16
  • Unless I'm wrong (which I usually am) it's perfectly fine to use `class` before a class name, like they used to do with `struct` in C. Also, many compilers will not complain if you don't return a value from `main`, and apparently [it compiles and runs fine on gcc](http://ideone.com/CIVd3), which one might find disturbing. But +1 anyway. – Seth Carnegie Nov 17 '11 at 05:18
  • @SethCarnegie, No, you're right. I just tried this on VC++ 2011 and it compiles and runs perfectly fine. I could've sworn the compiler used to nag at me when I missed the `return` in main. Today I learn ... – Zeenobit Nov 17 '11 at 05:21
  • The code compiles and run perfectly. The phrase "you cannot *addess* a null pointer" is not true. Actually you cannot **dereference** a null pointer, but -in fact- the OP code doesn't, since p->print() doesn't access any local member or calls any redirected (virtual) function. It is only from C++11 on that this had been formalized as "undefined behavior" (and since it is undefined, the fact it works isn't itself wrong!) – Emilio Garavaglia Nov 17 '11 at 15:41
  • It is perfectly fine to omit the `return` at the end of `main`: the standard states that if this is the case, the value returned will be `0`. – Luc Touraille Apr 30 '12 at 14:57
0

What you did is not a "good developed piece of code", but it works, because, even if the this pointer is null, you never (either explicitly or implicitly) dereferenced it.

your *p (or p->) is of class Test, and Test::print doesn't refer to anything inside Test, so ... since a null Test is always a Test and you don't care about its content, the code compile and works.

But this code will run into trouble if:

  • Test::print is made to be virtual: in this case p->print() (or (*p).print()) have to go through the v-table of the actual object to detect which function to call. (*p can be whatever Test-derived), but since there is no object, no v-table can be detected, and the program will crash.
  • Test is made to have a member, and your print function made to print it: in this case, since p points to an invalid memory block, your function -wile accessing the member variable- will try to implicitly dereference a null this pointer to calculate where the member is. And will result in an invalid memory address, thus causing a crash.

In fact you just entered in that gray area called "undefined behavior": the language lawyers (the ones who wrote the specs) din't say anything about it (in particular: the never said "it is a (runtime) error to dereference an invalid pointer": they said "dereferencing an invalid pointer result in undefined behaviour" that barely means "we don't want tell you what should happen").

But since a compiler writer have to do something (the compiler cannot be "undefined"), since at compile time -while translating a line of code- they cannot know what the value of a pointer will be, they decided to translate the code any way.

And since the execution of the code doesn't break any process boundary, it doesn't crash. And since no "in process uninitialized space" is accessed, not messy values are seen and everything looks ok.

Welcome to the unmanaged languages word!

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63