gary said:
Hi,
We all know the below codes are dangerous:
{
int *p = new int;
delete p;
delete p;
}
That is only a textbook example illustrating a double delete. What is
dangerous in the real world are all kinds of hard-to-find bugs that
don't stand out like the above contrived example.
Also, note that /any use whatsoever/ of the value of p after the first
delete p expression is undefined. Not just double deletes. Even
comparing p to another pointer is undefined behavior.
So why compilers do not "p = NULL" automatically after programs do "delete p"?
Because that would not achieve any benefit for actual programs which
are not textbook examples.
The real problem is that the program may have copies of the pointer in
variables other than just p. These pointers may be hidden throughout
the network of live object's in that program's run-time space.
Assigning NULL to p won't do anything about these other copies.
One such trivial scenario is when deletion is wrapped behind a
function:
void ObjectFactory:
estroy(Object *x)
{
delete x;
}
Assigning NULL to x here won't do anything useful, because the scope is
ending. The caller can still write:
factory->Destroy(obj);
factory->Destroy(obj);
Both x and obj are copies of the same pointer; assigning to local
variable x does nothing about obj still having a copy of that now
invalid value.
Also, the argument to delete might not be a modifiable lvalue.
int *const ptr = new int[10];
delete ptr;
ptr = 0; // error, it's a const!
The argument to delete might contain conversions so that it's not an
lvalue:
// p is a (void *), but we know it points to an object of SomeClass
delete (SomeClass *) p;
((SomeClass *) p) = 0; // error, assignment to non-lvalue
Lastly, consider that delete can be a user-defined operator. If it
performed this type of assignment in some conditions, would
user-defined allocators override it?
The delete operator shouldn't be regarded as a deallocating function
but as an annotation which says "the object referenced by this pointer
won't be touched by the program any longer". If the delete operator has
no effect on the value of a variable, then we can ignore the annotation
and use an alternate means of computing the object lifetimes.
Suppose that the we replace the global delete operator with one that
does nothing, and add a garbage collector underneath. We suspect that
the program contains bugs, such as uses of objects that have been
deleted, and multiple deletes. But these problems are ironed out with
the garbage collector. The assigning delete would interfere with this
solution. It would leave the suspicion that some pointers that are
overwritten with null by delete will be dereferenced.