Some programmers like to set a pointer variable to null after releasing the pointee:
delete ptr;
ptr = 0;
If someone tries to release the pointee again, nothing will happen. In my opinion, this is wrong. Accessing a pointer after the pointee has been released is a bug, and bugs should jump in your face ASAP.
Is there an alternative value I could assign to a pointer variable that designates released 开发者_JAVA百科pointees?
delete ptr;
ptr = SOME_MAGIC_VALUE;
Ideally, I would want Visual Studio 2008 to tell me "The program has been terminated because you tried to access an already released pointee here!" in debug mode.
Okay, it seems I have to do the checking myself. Anything wrong with the following template?
template <typename T>
void sole_delete(T*& p)
{
if (p)
{
delete p;
p = 0;
}
else
{
std::cerr << "pointee has already been released!\n";
abort();
}
}
No. Test for "0" when trying to delete
something if you really want to warn or error out about it.
Alternatively, during development you could omit ptr = 0;
and rely on valgrind to tell you where and when you're attempting a double free. Just be sure to put the ptr = 0;
back for release.
Edit Yes, people I know C++ doesn't require a test around delete 0
;
I am not suggesting if (ptr != 0) delete ptr;
. I am suggesting if (ptr == 0) { some user error that the OP asked for } delete ptr;
Assign NULL
after releasing a pointer. And before using it, check for its NULL
ity.. If it is null, report an error by yourself.
Is there an alternative value I could assign to a pointer variable that designates released pointees?
Ideally, I would want Visual Studio 2008 to tell me "The program has been terminated because you tried to access an already released pointee here!" in debug mode.
You get this very likely by just doing delete ptr
. The run-time will catch you if you double-delete this pointer.
Anyway, I don't think I have written ptr = NULL
more than a handful of times in the last decade. Why would I do this? Such a pointer is certainly hidden within an object whose destructor will delete the object it refers to, and after that destructor has been invoked the pointer is gone, too.
And if some circumstances would require me to leave a pointer to hang around after the pointee has been deleted, I wouldn't set it to NULL
simply because I would want the code to crash ASAP if I'd double-delete. Setting the pointer to NULL
just masks an error.
Of course, all this doesn't mean that one wouldn't want a pointer that might be explicitly set to "nothing", and use NULL
for that. But not to mask a double-deletion error.
No, calling delete
on a null pointer is perfectly normal from C++ point of view. Assigning some magic value will break code severely - you'll now have to distinguish between null pointers, valid pointers and magic value pointers and I guess it will be a huge mess.
If you really oppose deleting a null pointer you can have a separate boolean flag together with each pointer meaning that it has been delete
d. Perhaps you could write a wrapper class for that.
If you just want to check allocations and deletions the easiest way is to write your own global operator new
and operator delete
and manually keep track of all pointers that are allocated and deallocated.
Of course, you can also use an existing tool that does that for you, e.g. Valgrind.
If you also want to protocol each pointer access, this gets hairy. You essentially have to either patch the executable or execute it in a virtual machine where each pointer access is redirected to your bookkeeping routine.
But once again, existing tools such as Valgrind already do that for you. In the case of Valgrind, your executable is run inside a virtual machine; other programs go the way of patching your application by modifying the byte code.
When you delete a pointer in debug mode, many compilers will paint the bytes with some values to indicate the memory as "invalid" in case you try to read it. Of course genuine memory may have those bytes, so it allocates a bit extra to indicate whether the pointer you are reading is valid or not, and paints the bytes you do not directly access.
It is not wrong to call delete multiple times on the same pointer (variable) just on what it points to.
Maybe this isn't the best way to do this but it's totally legal of course...
T * array[N];
for( i = 0; i < N; ++ i )
{
array[i] = new T;
}
T* ptr;
for( i = 0; i < N; ++i )
{
ptr = array[i];
delete ptr;
}
and apart from not being the best way to do things, I am calling delete on the variable "ptr" multiple times but on different addresses and clearly not an error.
I think sharptooth already provided a valid answer, but I think he failed to spell it out explicitly:
If it is an error in your code to access a pointer variable after its object has been deleted via that pointer variable, then you have to add some checking yourself. (Possibly via some flag.)
Answering the question in question[sic].
No, there's no established value for released pointers.
I think any access to an invalid pointer (like NULL) should be noted - not only accessing them after release, which may never happen if no (non-NULL) initialization takes place. The debugger is bound to warn you when you try to access a null pointer - if it doesn't, you shouldn't be using it.
edit: end of answering the original question; rambling about double-delete
It really depends on the design if delete
on NULL
is a bug waiting to happen. In many cases it's not. Perhaps you should use "safe delete" when that is needed - or while debugging? Like this:
template <typename T>
void safe_delete(T*& ptr)
{
if (ptr == 0)
throw std::runtime_error("Deleting NULL!");
delete ptr;
ptr = 0;
}
There is no point.
I won't enter the apparently rather hot conversation going on, just point out an obvious fact: pointers are passed by copy.
With some code, it gives:
T* p = /* something */;
T* q = p;
delete q;
q = 0;
Do you feel safe ?
The problem is that you have no way to ensure that your magic value has been propagated to all pointers to the object.
This is like plugging a hole in a sieve and hoping it'll stop the water from pouring out.
In C++0x, you can
delete ptr;
ptr = nullptr;
Setting the pointer to a specific value will only affect this copy of the pointer, so it provides nearly no protection. If the program needs to be verifiably correct, there are smart pointer classes that track copies of the pointer and invalidate those, otherwise I'd just recommend a tool like Valgrind (on Linux) or Rational Purify (on Windows) that will let you check for memory access errors.
It’s not an error to delete
a nullpointer; by definition it does nothing.
Generally it’s a Bad Idea™ to null pointer variables after delete
, because there the only effect it can have is to hide a bug that causes multiple deletion (with the pointer variable nulled the second deletion will have no effect, instead of e.g. crashing).
Generally, nulling of pointers belongs, in my view, with all the other Microsoft’isms such as Hungarian notation and extensive use of macros.
It’s something that may once have had a good rationale, but which today, as of 2011, just has negative effects, and is used out of sheer inertia: idea propagation of the same kind that Knuth once described for random generators – the almost worst possible one gaining popularity and then incorporated as the default generator in umpteen language implementations and libraries, with most people thinking the extensive usage meant it had to be at least reasonable.
However, having said that, for the person who leans towards the ultra-formally pedantic it can be at least an emotionally satisfying idea to null pointers in e.g. a std::vector
, after delete
. The reason is that the Holy Standard, ISO/IEC 14882, allows the std::vector
destructor to do rather unholy things, such as copying the pointer values around. And in the formally pedantic view, even such copying of invalid pointer values incurs Undefined Behavior. Not that it is a practical concern. First of all I know of absolutely no modern platform where copying would have any ill effect, and secondly so much code relies on standard containers behaving reasonably that they just have to: otherwise, nobody would use such an implementation.
Cheers & hth.
精彩评论