Why doesn't free(p) set p to NULL?

2019-01-18 20:43发布

Any reasons why this can not be standard behavior of free()?

multiple pointers pointing to the same object:

#include <stdlib.h>
#include <stdio.h>

void safefree(void*& p)
{
    free(p); p = NULL;
}

int main()
{
    int *p = (int *)malloc(sizeof(int));
    *p = 1234;
    int*& p2 = p;
    printf("p=%p p2=%p\n", p, p2);
    safefree((void*&)p2);
    printf("p=%p p2=%p\n", p, p2);
    safefree((void*&)p); // safe

    return 0;
}

assignment from malloc demands cast from void*

vice versa:

safefree() demands cast to void*& (reference)

9条回答
劳资没心,怎么记你
2楼-- · 2019-01-18 20:51

What's this maniac thing with zero ? There are other numbers !

Why should a free pointer should contain zero more than any other distinguished value ?

Practically, in my C++ code I often use watchdog objects and when freeing a pointer reset it not to zero but to the watchdog. That has the added benefit that the methods of the object can still be called with the existing interface and is much more secure and efficient that resetting pointer to zero (it avoid testing objects for zero, I just call the object).

If a free like function say zfree(void * & p) would set p to zero it would forbid my watchdog style (or at least would'nt help).

And as others pointer out , what would be the point to reset a pointer to zero if it goes out of scope ? Just useless code. And what if there is other pointers that contain the same adress, etc.

查看更多
做自己的国王
3楼-- · 2019-01-18 20:55

C function parameters are always passed by value, so in order to modify the pointer passed to free() you would need to pass a pointer to the pointer being deallocated, which can lead bugs caused by forgotten & operators.

Secondly, if that pointer had any aliases, the programmer would still be responsible for nulling them out. I could see problems caused by programmers assuming that all references were set to NULL.

Finally, it's not always necessary to set the pointer to NULL. Imagine a function which allocates some memory, does some work and frees it before returning. I could see how setting the pointer to NULL might not seem optimal.

查看更多
Melony?
4楼-- · 2019-01-18 21:02

Bjarne Stroustrup discussing whether the delete operator should zero its operand. It's not the free() function, but it's a good discussion anyway. Consider points like:

  • What would be zeroed out if you said free(p + 1)?
  • What if there are two pointers to the memory? Why only set one to null if a dangling reference is still left behind?

He also says it was intended but never happened with operator delete:

C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn't seem to have become popular with implementers.
查看更多
够拽才男人
5楼-- · 2019-01-18 21:07

With reference to the quote from Stroustrup about delete, Peter Norvig also makes a similar remark. He writes (not about C++!):

"Nothing is destroyed until it is replaced"
 - Auguste Comte (1798-1857) (on the need for revolutionary new
   theories (or on the need to do x.f = null in garbage-collected
   languages with destructors))

In my C code, I find the following macro very useful:

#define free(p) free((void *)(p)),(p)=NULL /* zero p */

This, as written, uses its argument twice. But this isn't a problem, as any usage such as free(p++) or free(find_named_object("foo")) will give a compile-time error (lvalue required). And you can hide the macro by using (free)(p++), or by calling it something else e.g. FREE.

查看更多
不美不萌又怎样
6楼-- · 2019-01-18 21:07

Casting the reference from int *& to void *& is not guaranteed to work. int * simply does not have to have the same size, representation nor alignment requirements as void *.

The proper C++ solution would be to use templates, as Neil Butterworth suggests in a comment. And neither of these ways work in C, obviously - which is where free() comes from.

查看更多
做自己的国王
7楼-- · 2019-01-18 21:09

Simple answer: because you might be freeing an expression, e.g. free(find_named_object("foo")).

In more detail: The free function takes a void* parameter, which is the address of the memory to free. This doesn't confer to the function any knowledge of the original variable that supplied the address (or, for that matter, whether there even exists a variable). Just setting the parameter passed in to NULL would do nothing either, since it's just a local copy of the address.

查看更多
登录 后发表回答