This page is offered as a service of Bristle Software, Inc. New tips are sent to an associated mailing list when they are posted here. Please send comments, corrections, any tips you'd like to contribute, or requests to be added to the mailing list, to tips@bristle.com.
Last Updated: 12/6/1998
Applies to: ANSI C++, VC4.2+
It is a good idea to zero a pointer after calling delete to release the memory it points to. Otherwise you may accidentally continue to use the pointer after deallocating the memory. This is a particularly difficult bug to find because the memory is still there and still has the same contents, until that memory happens to be reallocated for an entirely different purpose by another part of the program. If no other part of the program allocates the memory right away, the program may continue to run correctly until a much later point in its execution. Even if the memory is reallocated and updated, you may not get an immediate error. Data values will be mysteriously wrong (changed by the other part of the program). If the memory contains pointers, their values will be mysteriously changed, and your code may then follow the "pointers" and attempt to access, update, or even execute data at random locations. Not a good scene! In the worst case, a program with a bug like this may appear to work properly for years, and only fail when a totally unrelated change is made that causes data to occupy different addresses in memory. This leads to cases like adding a single print statement and causing old well-tested code to fail. Ouch!
To avoid, this problem, I took a tip from the Ada language (which automatically zeroes each pointer passed to its equivalent of delete). I wrote the following C++ macros and use them in place of the regular delete and delete [] in all my code:
I replace all of my:
delete p; delete [] p;
lines with:
MY_DELETE (p); MY_DELETE_ARRAY (p);
Here are the macros:
// --------------------------------------------------------------------- // MY_DELETE and MY_DELETE_ARRAY // --------------------------------------------------------------------- // Calls delete and zeroes the pointer. // --------------------------------------------------------------------- #define MY_DELETE(ptr) { if ((ptr)) { delete (ptr); (ptr) = 0; } } #define MY_DELETE_ARRAY(ptr) { if ((ptr)) { delete [] (ptr); (ptr) = 0; } }
Note that the macros only delete the pointer that is actually passed to them, so if you have 2 pointers to the same thing, you still have to zero the other pointer manually. For example, in a linked list, the head pointer might point to the same thing as the pointer that you use to iterate over the list elements. If you delete all list elements via the iterating pointer, you still need to zero the head pointer.
Note: Don't name the macro simply DELETE if you want it to work on Windows. The standard Windows header files define another macro called DELETE for other reasons. Thanks to Howard Kapustein for reminding me of this.
--Fred
©Copyright 1998-2021, Bristle Software, Inc. All rights reserved.