2

In my opinion following program should be crashed but its not only working but showing the right result("derv is called").

#include <iostream>
using namespace std;
class base 
{
 public:
  virtual ~base(){}
};
class derv: public base 
{
 public:
   void f() { cout << "derv is called" <<endl;}
};
int main() {
  base* p = new base();
  derv *d1 = dynamic_cast<derv*>(p);

 // Since p point to base , so d1 should return nullptr 
 //calling any function using d1, should fail/crash 
 //but why the following line is working ?? 

 d1->f();
}

Sorry I forgot to add few lines in my previous post: If I add a single data member and try to access it, gives me segmentation fault, which I think is the correct behavior. My Question is that why accessing data member changes the behavior ? When variable is not get accessed , calling "f()" function is successful while the same function "f()" gives segmentation fault when accessing with the data member? Is it the undefined behavior?

class derv: public base 
{
 public:
  int x = 0 ; // Added new member,  c++11
  void f() { cout << "derv is called " << x << endl;} //access it here
};
Alok
  • 1,997
  • 2
  • 18
  • 30
  • 1
    How do you know `d1` is null? You don't check it, and your function doesn't use the `this` pointer in any way, so it's within the realm of possibility that it won't crash, even if it's null. https://ideone.com/K2dTD7 And here's a crash: https://ideone.com/US5s6r – Retired Ninja Mar 24 '18 at 00:05
  • 1
    It is Undefined behavior. – Raindrop7 Mar 24 '18 at 00:05
  • Once more, Undefined Behavior means anything can happen - including seeming to "work". – aschepler Mar 24 '18 at 00:09
  • 2
    There is no "should crash" in C++. A "should crash" *can* make sense if you are talking about a specific implementation of a C++ compiler, with specific flags, a specific operating system or a specific memory situation. But there are no mandated crashes in the language specification. – Christian Hackl Mar 24 '18 at 00:17
  • I updated my question – Alok Mar 24 '18 at 00:23
  • Now I tried to run the above program after adding and accessing a single variable, it always give me segmentation fault. It it a undefined behavior? – Alok Mar 24 '18 at 00:34
  • 1
    Many duplicates - [here](https://stackoverflow.com/questions/11320822/why-does-calling-method-through-null-pointer-work-in-c), [here](https://stackoverflow.com/questions/2505328/calling-class-method-through-null-class-pointer), [here](https://stackoverflow.com/questions/2533476/what-will-happen-when-i-call-a-member-function-on-a-null-object-pointer) – Tony Delroy Mar 24 '18 at 01:29

2 Answers2

3

f is not a virtual function. The program does not have to look for the virtual function table when trying to call f, so the method is called anyway.

If you try to check the pointer value of this inside of f, it will be nullptr.

Nican
  • 7,825
  • 3
  • 27
  • 26
  • Just out of curiosity, null or just trash? Or compiler dependent UB? – Mad Physicist Mar 24 '18 at 00:07
  • 2
    If dynamic_cast fails the result is null. – Retired Ninja Mar 24 '18 at 00:09
  • 2
    `nullptr` to pick a bit on details. – super Mar 24 '18 at 00:10
  • 1
    @RetiredNinja: I think it is undefined behavior. – Raindrop7 Mar 24 '18 at 00:11
  • The result of checking `this` inside of `f` might depend on exactly how you check it. A compiler is allowed to optimize `if (this)` to do the same as `if (true)`, since there's no legal way to have `this` be a null pointer value. – aschepler Mar 24 '18 at 00:12
  • @super There is no `nullptr` involved here. `nullptr` is a keyword. Pointer objects can have null pointer values. – aschepler Mar 24 '18 at 00:12
  • @aschepler You are not wrong. Still it is involved in the sense that you would use `nullptr` to check if a pointer object has a null pointer value. – super Mar 24 '18 at 00:25
  • @aschepler You are not wrong. Still it is involved in the sense that you would use `nullptr` to check if a pointer object has a null pointer value. – super Mar 24 '18 at 00:25
3

It is undefined behavior in your program you dereferencing d1 which is a NULL pointer:

base* p = new base();
derv *d1 = nullptr;
d1 = dynamic_cast<derv*>(p);

if(nullptr == d1) // condition succeeds which means d1 is nullptr
    cout << "nullptr" << endl; 

A safe programming is the task of the programmer not the compiler's so a good program checks before uses:

// avoiding error prones and UBs
if(nullptr != d1)
    d1->f();
Raindrop7
  • 3,889
  • 3
  • 16
  • 27
  • In practice, your second example either postpones the undefined behaviour or trades it for specified but undesired behaviour. An unexpected null pointer is a bug, so `assert(d1 != nullptr);` should be used. – Christian Hackl Mar 24 '18 at 00:18
  • You mean I should use: `if(nullptr != d1) d1->f();`? – Raindrop7 Mar 24 '18 at 00:20
  • Well, I'd say that `if (d1)` is already idiomatic in C++. Trying to `if (d1 != nullptr)` is wordier, but I don't see it as arguably better. Depends on which way your OCD falls. – Eljay Mar 24 '18 at 00:40
  • `if (derv* d1 = dynamic_cast(p)) ...` is IMHO nicer - limits the scope of `d1` to the `if` test/statements, and if you get in the habit of writing your dynamic casts like this you can't accidentally use a `nullptr` `d1` – Tony Delroy Mar 24 '18 at 01:35
  • @Raindrop7: First of all, you should use `if(d1 != nullptr)` and not `if(nullptr != d1)`. The latter form of equality comparisons was sometimes recommended 20 or 30 years ago, when compilers didn't warn about accidental assignments, but nowadays it just looks funny. As for whether to compare with `nullptr` at all or just write `if (d1)`... well, I usually prefer the former form because it's more readable. – Christian Hackl Mar 24 '18 at 11:45