19

I've experienced an issue where in a constructor, I was using the this pointer, but the this pointer happened to be null at that time. For example:

MyClass::MyClass()
{
   // The 'this' pointer happened to be null in this case,
   // and the program crashed inside 'm_callbackfunc' because
   // it does not handle null input.
   m_callbackFunc(this);
}

Why can the this pointer be null? In which case does that ever happen?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
user454083
  • 1,337
  • 3
  • 16
  • 31
  • 5
    Are you sure it is null? – Ed Heal Jul 10 '15 at 08:46
  • Xcode LLDB claims this is NULL if I step into MyClass constructor – user454083 Jul 10 '15 at 08:50
  • 2
    All the data members of MyClass are guaranteed to be initialized by the time the body of the constructor is executed, and therefore the object is fully constructed and you should be able to call "this" without problems. So the problem must be somewhere else. – Francis Moy Jul 10 '15 at 08:51
  • 5
    Unless you force it, `this` should not be null. Show us how the problematic instance of `MyClass` is constructed. – Beta Carotin Jul 10 '15 at 08:51
  • You don't commit class suicide (`delete this`) in the constructor anywhere do you? I've seen it before, gotta ask ... – txtechhelp Jul 10 '15 at 08:55
  • 1
    @user454083 `Xcode LLDB claims this is NULL if I step into MyClass constructor` Maybe it is an issue with your debugger and not an issue with the program. Why not output the value of `this` instead of using the debugger? – PaulMcKenzie Jul 10 '15 at 09:12
  • @PaulMcKenzie OP claims his program crashes, so it looks like `this` really is null. – Beta Carotin Jul 10 '15 at 09:35
  • Now, the real question is why are you passing `this` to a member function?! – Nasser Al-Shawwa Jul 10 '15 at 09:36
  • @Nasser: It is not a member function, it is a constructor. Maybe they are using placement `new`... – rodrigo Jul 10 '15 at 09:38
  • Thanks for everyone response. I think I kinda have clue where can be the root cause, actually there is an operator new overwritten somewhere I didn't handle it correctly. You are write, this shouldn't be null, although Xcode claims so, but the problem is somewhere else. – user454083 Jul 10 '15 at 09:39
  • @rodrigo, I'm not talking about the constructor, but the line `m_callbackFunc(this)`. The `m_` prefix implies it's a member function, so passing `this` is not required. – Nasser Al-Shawwa Jul 10 '15 at 09:40
  • @Nasser No, `m_` indicates a member, not a member function. Perhaps a member function _pointer_. – Beta Carotin Jul 10 '15 at 09:41
  • This is presuming that this is the case. It is possible to define this as a method for the class, a static member or even a global function, Besides would your hypothesis it would be as a part of the initialiser list – Ed Heal Jul 10 '15 at 09:45
  • @txtechhelp, `delete this` would not change the value of `this` it would only destroy the object it points to. You can't change the value of `this` as it isn't a variable that can be written to, it's a prvalue expression that evaluates to the object's address. – Jonathan Wakely Jul 10 '15 at 10:13
  • 2
    @JonathanWakely: IIRC depending on calling convention `this` can actually passed be as hidden parameter. Meaning while it is technically not a variable, it can correspond to some (memory) location at method level and in this case it might be possible to zero/change it. It is land of undefined behavior, of course. – SigTerm Jul 10 '15 at 18:12
  • @SigTerm that would still assume an implementation that modifies the operand of `delete` and I don't think such implementations exist. Scribbling over the stack could zero the location storing the hidden parameter, sure, but that is still unlikely to have anything to do with `delete this`. – Jonathan Wakely Jul 11 '15 at 11:38

4 Answers4

12

The only way a this pointer can be NULL is if some code in the program has exhibited undefined behaviour.

It might for example be achieved by something like

  void *place = nullptr;
  MyClass *object = new (place) MyClass();

The problem is that this effectively dereferences a NULL pointer, so has undefined behaviour. So it is possible that MyClass constructor will have this as NULL. Any other effect is also possible - such is the nature of undefined behaviour.

Some debuggers also report this to be a NULL pointer. But that isn't actually a sign of this being NULL. It is a sign that this is a language keyword rather than something with a symbolic name in object files that the debugger can find. Some other debuggers, when asked to evaluate this simply report that nothing with that name exists in the current function/scope/whatever - possibly because the C++ compiler implements this by passing a value in a machine register.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • 1
    Technically, all versions of the C++ standard say that the compiler must not call the constructor in that case, see http://stackoverflow.com/questions/17571103/passing-null-pointer-to-placement-new (that was changed by DR 1748). Post-DR1748 it's undefined behaviour, so the constructor might get called with a null pointer if your compiler already implements that DR already. – Jonathan Wakely Jul 10 '15 at 10:11
  • Yeah ... It's not something I've gone out of my way to test, but at least a couple of compilers crash miserably with code like I describe - consistent with what they do dereferencing NULL or other comparable instances of undefined behaviour. So, odds are, that TR will not result in many compilers changing what they do - it just confirms that such things are bad ideas. – Peter Jul 10 '15 at 10:55
  • The last bit is perhaps somewhat misleading. Debuggers are perfectly capable of dealing with variables existing in registers. However, the problem is that `this` isn't a real variable, and may in fact not exist at all. Not in a register, and not in memory. – MSalters Jul 10 '15 at 12:14
  • 1
    @Peter, "will not result in many compilers changing" is wrong, because Clang and GCC historically both performed the required check ([example showing no output](http://coliru.stacked-crooked.com/a/8a375a99d4930eea)), and Clang already _did_ change for the next release (3.7.0), and GCC will do too at some point ([PR35878](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35878)), because removing the no-longer-required check can improve performance (as discussed in the question I linked to). – Jonathan Wakely Jul 10 '15 at 13:43
  • What probably _will_ crash on all compilers is dereferencing `object` after the placement-new, because it's a null pointer and no object got constructed at that address. But with current releases of both gcc and clang the behaviour of the code you show is perfectly well-defined and will not run a constructor and will not crash. – Jonathan Wakely Jul 10 '15 at 13:45
7

In which case the C++ this pointer can be NULL

this can be null if you call a class method through a null pointer.

SomeClass *a  = 0;
a->someMethod();//kaboom

While you definitely should NEVER be doing that, in practice you can even accientally get away with this without crashing (good luck catching that later) if someMethod doesn't access any object fields. (Just don't do that, alright?)

Whether it is defined behavior or not is a different subject altogether. Most likely it is undefined behavior.

However, that does not usually happen from within a constructor (I think I only saw null this in a constructor when something threw an exception in a constructor. That happened long ago, so I don't even remember details anymore). Which means something weird is going on. You could be trying to cast this to something, something might be corrupting stack, accessing program variables via different thread, and so on. With the mount of code you provided it is impossible to guess what the problem here is.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
SigTerm
  • 26,089
  • 6
  • 66
  • 115
  • 2
    The question is using the a constructor. i.e. not a method – Ed Heal Jul 10 '15 at 11:13
  • 4
    @EdHeal: That's nitpicking. If you want more nitpicking, the question asks when this can be null. Not when this can be null in constructor. – SigTerm Jul 10 '15 at 11:48
  • 2
    It is calling a function with the parameter being `this`. This is occurring in a constructor. So then can this be null? Your answer does not answer the question – Ed Heal Jul 10 '15 at 11:54
  • @EdHeal : constructors **are** methods. They're non-data class members. And as Peter's answer shows, it's not hard (but very illegal) to call them on a nullptr. – MSalters Jul 10 '15 at 12:18
  • @MSalters, as my comment on Peter's answer shows, until a few months ago compilers were required **not** to run the constructor in Peter's example (Clang trunk has been changed fairly recently so that it now does run it with a null `this`). So I think it makes sense to distinguish calling a member function through a null pointer (just a programming error) and constructing an object at the address zero (historically actually quite hard to do, although now possible, and undefined, using placement-new). – Jonathan Wakely Jul 10 '15 at 13:47
  • 1
    @EdHeal: Constructor is a method for most practical purposes. There's some syntaxic sugar and some limitations, but it is a block of code that may or may not be inlined, has local variables etc. `this` also can be turned into variable by compiler (stored in certain location, register) and that location can be zeroed by various magic methods like dangling pointer. Also, you do remember that `this` often is pretty much a simple hidden 1st parameter in the method, right? Of course all this is the land of undefined behavior, but lots of stuff can occur during everyday practice. – SigTerm Jul 10 '15 at 18:07
3

According to Visual Studio, I had this being a nullptr when I wrapped the object in a unique_ptr and didn't initialize it properly, then later on called a method on it to see what would happen.

While this differs from the opening post, it satisfies the topic title (assuming VS2015 wasn't lying to me).

This was due to me doing something wrong outside of the code (as others have alluded to elsewhere).

Water
  • 3,245
  • 3
  • 28
  • 58
2

was it a recursive function? If it was then yes, this can be null when the runtime stack runs out of space. this is pushed on to the stack. Try to re-write the function iteratively.

class Class
{
public:
    void makeThisNull();
};

void Class::makeThisNull()
{
    makeThisNull();
}
// run this in a debugger and you will see it crash when this == 0x0 (nullptr)
int main()
{
    Class c;
    c.makeThisNull();
    return 0;
}