Can you call a method on a nullptr in C++?
Betteridge’s law of headlines and an idea of how methods work in most programming languages work you’d think the answer would be no. But the answer is closer to yes! I mean otherwise why even bother writing this? Technically what happens is undefined (so never rely on this behavior) but normally it works or at least it doesn’t crash immediately.
For example this program:
Produces this output.
❯ ./nullptr
constructed
I just print
I print the member variable
m_member: initialized
I just print
I print the member variable
[1] 39881 segmentation fault ./nullptr
This, at least to me, is counterintuitive. I first ran into this issue debugging a failed test that was segfaulting at strange place. It was in the middle of a method that was accessing a member variable. Before the failure the method had been called on stack allocated object but for various reasons someone had changed it to a pointer and it wasn’t being initialized. This test has some issues with layers of indirection so this wasn’t immediately obvious to the person changing things but that’s another issue.
Now at first I couldn’t understand why calling this method on a nullptr wasn’t crashing
until I remembered that C++ is different from other object oriented languages I’m used to.
Specifically, non virtual C++ methods aren’t dynamically dispatched.
This makes things faster
because there’s no work to dynamically figure out where the method is
all that’s needed is a callq __ZN3Foo13member_accessEv and we’re off.
Since that’s all that’s needed to call a method
and since doing any more could slow things down that’s all the compiler does.
Well generally.
One could probably do something different if they wanted
but most compilers are going to do this.
So where does the crash come from?
Like clearly you can’t access the member variable of the object that doesn’t exist
but what exactly is happening?
You can call a method on an object
that doesn’t exist so maybe there’s some other weirdness at play.
Most methods in object oriented languages have a keyword
like self or this
that let you refer to the object the method is being called on.
In some languages you have to mention the this or self to get an object’s property inside a method
but in most (that I’ve used) you
just need to use the properties name.
Regardless there needs to be a reference to the object
to find things out about the object like the values of the member variables.
In most languages the reference to the object is implicitly passed in to method
but in languages like python you need to let the language know you’re passing it
like so def method(self, other_parameters).
In C++ the reference to the object is called this
and it’s implicitly passed.
But it is passed!
And that’s where the crash happens.
During runtime the method tries to dereference the this pointer
plus the offset for the member you’re referencing.
this however is null so you’re really trying to reference something between
0x0 and 0x0 + sizeof(YourObject) which is still
in all likelihood not in your program’s memory space
so you get an access violation and crash.
I mentioned virtual methods earlier. When you invoke a virtual method on a nullptr you do crash immediately. Why the difference? Because virtual methods are dynamically dispatched! That’s why they exist! So there at least what I expect happen.
So to sum up you can call a non virtual method on a typed null pointer but the result is undefined.
Undefined generally means running the method ‘normally’
until you attempt to access a member variable
(or anything that would dereference the this pointer which includes things like virtual methods)
at which point your program will try and access NULL (or something close to it)
and crash.