Question

In this paragraph of C++ FAQ usage of delete this construct is discussed. 4 restrictions are listed.

Restrictions 1 to 3 look quite reasonable. But why is restriction 4 there that I "must not examine it, compare it with another pointer, compare it with NULL, print it, cast it, do anything with it"?

I mean this is yet another pointer. Why can't I reinterpret_cast it to an int or call printf() to output its value?

Was it helpful?

Solution

The reason that you cannot do anything with a pointer after you delete it (this, or any other pointer), is that the hardware could (and some older machines did) trap trying to load an invalid memory address into a register. Even though it may be fine on all modern hardware, the standard says that the only thing that you can do to a invalid pointer (uninitialized or deleted), is to assign to it (either NULL, or from another valid pointer).

OTHER TIPS

The value of 'this' after calling delete is undefined, and the behaviour of anything you do with it is also undefined. While I would expect most compilers to do something sensible, there's nothing (in the spec) stopping the compiler from deciding that its behaviour in this particular case will be emit code to format your hard-disk. Invoking undefined behaviour is (almost) always a mistake, even when your particular compiler behaves in the way you'd like it to.

You could work around this by taking a copy of the pointer (as an integer) before calling delete.

Aha!

3.7.3.2/4: "... the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined".

Note that this says "using the value", not "dereferencing the pointer".

That paragraph is not specific to this, it applies to anything that has been deleted.

because any action you can take with that pointer could trigger logic which is interpreted on the class methods of that object, which could lead to a crash.

Now, some of the actions you point at could be apparently "safe", but it's difficult to say what happens within any method you can call.

From the post: "must not examine it, compare it with another pointer, compare it with NULL, print it, cast it, do anything with it"?

All these actions can trigger operator related functions, which are evaluated with an undefined pointer. Idem for casting.

Now if you perform a reintepret_cast, that's probably a different story, and you could probably get along with it, as reinterpret is just a bit by bit reinterpretation, without involving (as far as I know) any method call.

For the same reason you would not delete any other pointer and then try and perform any operations on it.

b/c the address that this refers to now, it undefined, and you don't know what might be there...

In a multi-threaded program, the moment you delete a pointer, the free space can be allocated by another thread, overwriting the space used by this. Even in a single-thread program, unless you're very careful about what you call before returning, anything you do after delete this could allocate memory and overwrite what used to be pointed to by this.

In a Microsoft Visual C++ executable compiled in Debug mode, deleteing a pointer causes its memory to be immediately overwritten with a 0xCC test pattern (uninitialized variables are also initialized with this pattern), to help in identifying dangling pointer bugs such as this one.

This reminds me of when I fixed a bug in a online-playable game in which a Fire object's constructor deleted the oldest Fire if the total number of Fires had reached a certain number. The deleted Fire was sometimes the parent Fire creating a new Fire — bam, dangling pointer bug! It was only due to luck that this bug interacted with the memory allocation algorithm in a completely predictable way (the deleted Fire was always overwritten with a new Fire in the same way) — otherwise it would have caused a desynchronization between online players. I found this bug when rewriting the way the game did memory allocation. Due to its predictability, when I fixed it, I was also able to implement emulation of its behavior for compatibility with older game clients.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top