0

I stumbled upon some strange behaviour while experimenting with dynamic_cast. This is the code i have

struct Base
{
    virtual ~Base(){}    
    virtual void output() = 0;
};

struct Derived1 : public Base
{
    void output() {}    
    void doDerived_1()
    {
        std::cout << "derived 1\n";
    }
};

struct Derived2: public Base
{ 
    void output() {}
    void doDerived_2()
    {
        std::cout << "derived 2\n";
    }
};     

int main()
{
    Base* base = new Derived1();
    Derived2* der2 = dynamic_cast<Derived2*>(base);
    // der2 = 0
    der2->doDerived_2();
}

Even though der2 is equal to 0 doDerived_2() will still be called and any code inside of it will be executed. The code breaks when i call output() function instead.

Can someone explain to me why this works and doesn't break when it clearly should? Thanks

  • 3
    Undefined behaviour. But you should check if a cast succeeds before using the result. – juanchopanza Jun 05 '14 at 12:34
  • It is undefined behavior to dereference the `nullptr`! – πάντα ῥεῖ Jun 05 '14 at 12:34
  • There was correct answer here, but it was downvoted and deleted..., – Agent_L Jun 05 '14 at 12:36
  • 1
    @Agent_L, It's not correct in terms of the standard. I mean explanation is fine, but acting like that's guaranteed to happen without even mentioning that this is undefined behaviour isn't. – chris Jun 05 '14 at 12:38
  • 1
    @Agent_L The answer was incorrect. That is why it was down-voted. – juanchopanza Jun 05 '14 at 12:39
  • [This question](http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-beha) has a pretty good answer that even takes into account that dereferencing a null pointer has some exceptions to being undefined behaviour. Calling a member function on one always is, however. – chris Jun 05 '14 at 12:43
  • @chris As I remember it did not state that this behavior was guaranteed, it merely explained "why this works and doesn't break". Without addressing the "when it clearly should" issue, though. – Agent_L Jun 05 '14 at 13:36
  • @Agent_L, It gave *one* possible reason for why this works. It really wasn't clear at all in saying the behaviour is not guaranteed, though. – chris Jun 05 '14 at 13:50

2 Answers2

3

Your code has undefined behaviour, because you are dereferencing a null-pointer.

However, a possible implementation for member function invokation is through the thiscall calling convention, which implicitely passes the object pointer as the first parameter. If your function does not access any member variables, the this pointer is not dereferenced, and the function might execute as expected. It has nothing to do with dynamic_cast.

Note that this is not guaranteed in the standard

Example:

struct Foo {
    int doIt() {return 42;}
};

int main() {
    Foo *f = NULL;
    std::cout << f->doIt();
}

Prints 42 on some compilers

king_nak
  • 11,313
  • 33
  • 58
2

You are dereferencing the null pointer. The behavior of such an operation is undefined. In this case it happens to call the method with this being the null pointer. However, anything could happen.

If you want an exception to be thrown instead, cast references:

Derived2& der2 = dynamic_cast<Derived2&>(*base);
der2.doDerived_2();

Alternately, you can use an if-statement to execute some code only if the cast succeeds:

if (Derived2* der2 = dynamic_cast<Derived2*>(base)) {
    der2->doDerived_2();
}
  • I know I should check for pointer validity before calling any of the member methods. I was just confused that when the pointer is 0 it still worked. @king_nak example was a good explanation for this behaviour. – Max Mustermann Jun 05 '14 at 13:11