views:

767

answers:

6

I was given the following as an interview question:

class A
{
public:
    void fun()
    {
        std::cout << "fun" << std::endl;
    }
};

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

What will happen when this code is executed, and why?


See also:

+1  A: 

We can't know what will. Everything can happen, because the program exposes undefined behavior. See Does invoking a member function on a null instance cause undefined behavior?.

Johannes Schaub - litb
+2  A: 

It won't compile.

  1. there is a typo in the Class keyword, which should be lowercase.
  2. fun() is private.
  3. If you solve those two minor problems, it will run, and print "fun", because:
    • C++ doesn't check whether the pointer is NULL before calling the function
    • fun() is not virtual, so there's no need to refer to a vtable to call fun()
    • fun() never access any member variables in A so it doesn't need to dereference the null this pointer.
Ken Bloom
3. `A* a = NULL; a->fun();` is illegal outside of a function body.
sepp2k
@sepp2k, good point.
Ken Bloom
But I think we still can bend our minds and sort of understand what he meant
henle
+28  A: 

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).

sth
Where is the address of the member function stored for a C++ class and how can it be accessed using the NULL pointer to the object of that class?
Kamal
@Kamal If the function is not virtual, then it gets statically linked. No need for a table. No need for the object pointer.
Frank Krueger
@Kamal The compiler could use static information (it knows the pointer is of type A) to find the function. The fact that the compiler can do this does mean that it must, and does not prevent this from being undefined behaviour.
anon
@Kamal: Who said it must be stored? The compiler can transform the function call into `A::fun(a)`.
KennyTM
@Kamal: The compiler knows the type of the object and the address of the method that should be called at compile time and can insert that address "hard coded". There is no need to look anything up at runtime. (This doesn't mean the compiler *has* to do it that way, but it could.)
sth
Got it.. Thanks a lot!
Kamal
+2  A: 

Others have pointed out many issues - let me just throw in my association for "tricky": (supposed you change Class to class) it depends on how NULL is defined ;-)

Evil example:

A anotherA();
#define NULL &anotherA;

...

OK, as I realize it wouldn't work this way directly, since you must put these two lines between the definition of class A and that of a... but I am fairly sure there is an evil enough way to actually make this technically possible :-(

Péter Török
NULL is simply 0 and I don't think this qn is that much tricky!
Rajendra Kumar Uppal
@Rajendra well, `NULL` is `#defined` as `0` with a preprocessor macro in one of the standard C header files, to be precise... so it _can_ be redefined (which of course should **not** be done in any serious program). And this just my 2 cents worth anyway - feel free to omit it :-)
Péter Török
Knew that! But this question doesn't have any problem with NULL. My curiosity is why it prints "fun". Can u tell me?
Rajendra Kumar Uppal
Johannes Schaub - litb
@Rajendra you haven't limited the level of "trickyness" in your post. Why it prints "fun" is because your compiler happens to do a bit of optimization which is not required by the standard, this is why it works for you (on this particular platform). This is already explained by @sth.
Péter Török
+1 for such en evil mind :)
Matthieu M.
@Johannes - wow. And you needn't even redefine the comma operator ;-)
Péter Török
@Peter, you and GMan and your comma operators :)
Johannes Schaub - litb
That's not a really universal NULL is it? How about `struct null { template<typename T> operator T*() const { return new T; } }; #define NULL null()`. Bonus memory leak for additional evil.
MSalters
A: 

Was this a question about your knowledge of C++ or a question about code reading skills and/or debugging skills? Other than the fact that a C++ class is being used, this kind of problem is language-agnostic.

Larry
Was this an answer?
Sorush Rabiee
@Larry No, it isn't.
anon
How is it language agnostic. On java, you can precisely say what happens (exception thrown).
Johannes Schaub - litb
+7  A: 

By the standard, this is undefined behavior and therefore a very bad thing. In reality of most programming platforms (across both X86 and several other architectures) this will run fine.

Why? Consider how class functions are implemented in C++. This isn't a virtual function, therefor this can be a static call to a known address. In assembly, we can see this as mov A, 0 mov ecx, A call a__fun

since a__fun requires no instance data, even though it receives a null this pointer, nothing will happen.

Still shitty code and any compiler will scream, but it can run.

Daniel Goldberg