0

why is this code practically reliably working, is not unstable, undefined? it's dereferencing unallocated, dangling pointers to objects. thanks.

#include <iostream>
using namespace std;

class Base{
    public:
    void vf()
    {
        cout<<"vf\n";
    }
    void pr(){
        cout<<"vb\n";
    }
};

int main() {
    Base* b ;

    //Base * bp = new Base;   //trying to disrupt memory
    char ar[]= "ttttttttttt"; //trying to disrupt memory

    b->pr();
    char aa[]= "ttttttttttt";
    b->vf();
    return 0;
}
Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
Petr
  • 11
  • 1
  • 3
    Does this answer your question? [What will happen when I call a member function on a NULL object pointer?](https://stackoverflow.com/questions/2533476/what-will-happen-when-i-call-a-member-function-on-a-null-object-pointer) – Mark Taylor Apr 08 '20 at 21:04
  • Your question claims the code is "reliably working" but also claims that it should be "unstable, undefined". So it's not doing what it should do. Why would you describe that as "reliably working"? I would describe that as not working as expected. – David Schwartz Apr 08 '20 at 21:14
  • well, works seemingl reliably because it repeatedly works correctly on ideone.com, and on code:blocks, where I was testing this. /c++14 – Petr Apr 09 '20 at 13:50

1 Answers1

4

Welcome to the Wonderful World of Undefined Behavior! According to the C++ spec, the behavior of this problem is undefined, so what you're seeing might work on your system but crash on others, or vice-versa.

Practically speaking, what's happening here is probably an artifact of how the compiler generates code for member functions. Typically, a member function that looks like this:

void doSomething() {
    cout << "Hello!" << endl;
}

would probably be compiled as if it were a free function like this:

void Base_doSomething(Base* this) {
    cout << "Hello!" << endl;
}

In that sense, when you write

bf->doSomething();

the compiler treats it as if you've written

Base_doSomething(bf);

and nothing bad happens, because Base_doSomething doesn't reference the this pointer, which is where all the bad things happen.

Now, this is very brittle. If you try to read any of the data members of the Base type, this code will crash because then you are reading from a bad pointer. Similarly, if doSomething were a virtual function, you'd get a crash because calling a virtual function (typically) requires reading from the receiver object to find the vtable to determine which function to call, and a dangling pointer will then lead to a bad memory access.

So, to summarize:

  • This code leads to undefined behavior, so the particular behavior you're seeing isn't guaranteed to happen or work across platforms.
  • Although syntactically bp->doSomething() looks like a pointer dereference, it might not actually involve a pointer dereference.
  • Member functions are typically compiled as free functions that have an "implicit this" pointer passed as a first argument.
  • Virtual functions work differently than this, so you'd expect to see different behavior there.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • wow. thank you for the expert explanation. I commented in this way here at time of asking, but somehow the comment is not showing here. – Petr Feb 25 '21 at 13:26