-1

In C++, why can a pointer assigned nullptr call member functions? I expected that the function will get an error when it is called since the pointer does not point the region of memory generated the instance of class.

The code I tried is as below:

#include <iostream>

class Foo
{
  public:
    int var = 10;
    void func();
};
void Foo::func() {
  std::cout << "func() function called." << std::endl;
}


int main(int argc, char const* argv[])
{
  Foo foo;
  Foo* foo_ptr = (Foo*) nullptr;

  // std::cout << foo_ptr->var << std::endl;  // segmentation fault
  foo_ptr->func();  // Output: "func() function called." WHY??

  foo_ptr = &foo;
  std::cout << foo_ptr->var << std::endl;  // Output: 10
  foo_ptr->func();  // Output: "func() function called."

  return 0;
}

Output:

$ g++ -O0 -Wall callSample.cpp && ./a.out
callSample.cpp:6:13: warning: in-class initialization of non-static data member is a C++11 extension [-Wc++11-extensions]
    int var = 10;
            ^
1 warning generated.
func() function called.
10
func() function called.

Environment:

$ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
fhiyo
  • 233
  • 4
  • 13
  • 2
    Undefined behavior is undefined. – user0042 Jul 23 '17 at 03:25
  • Because the addresses of member functions are static and they are not related to the pointer they are called with. That pointer is actually used as one of the member function's parameters (referred to as `this`). – Galik Jul 23 '17 at 03:28

1 Answers1

3

C++ member functions have an implicit this parameter. In your example, it's as if you wrote:

class Foo
{
  public:
    int var = 10;
    static void func(Foo* this);
};

You'd then call it by:

Foo* foo_ptr = nullptr;
Foo::func(foo_ptr);

And everything would be fine.

Since your function does not use this, the fact that it's null does not stop it from working. But that doesn't make the code legal--you have invoked Undefined Behavior as soon as you dereference a null pointer, as you have done here:

foo_ptr->

So while your code appears to work, it is not valid C++. If you want code similar to yours that is valid, you can use the above formulation, with a static member function taking an explicit this (which you can name anything you want, of course--only the regular implicit this has a fixed name).

When using the regular C++ member function with implicit this, it is a precondition that this is a valid object, and not null. Otherwise the call is invalid. Many implementations do not have an enforcement mechanism to check this, however, and so you see code that seems to work even though it is invalid.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436