为什么不将free(p)设置为NULL?

时间:2010-04-16 09:33:50

标签: c++ c memory-management memory-leaks free

为什么这不能成为free()的标准行为的任何原因?

指向同一对象的多个指针:

#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;
}

来自malloc

void*要求的转让

反之亦然:

safefree()要求投放到void*&(参考)

9 个答案:

答案 0 :(得分:28)

如果确实如此,则必须将指针传递给指向函数的指针:

int * p = malloc( sizeof( int ));
free( & p );

我相信很多人会出错。

答案 1 :(得分:27)

简单回答:因为你可能正在释放一个表达式,例如: free(find_named_object("foo"))

更详细:free函数采用void*参数,该参数是要释放的内存的地址。这并不赋予函数任何提供地址的原始变量的知识(或者,就此而言,是否存在变量)。只是将传入的参数设置为NULL也不会做任何事情,因为它只是地址的本地副本。

答案 2 :(得分:15)

Bjarne Stroustrup discussing whether the delete operator should zero its operand。它不是free()函数,但无论如何它都是一个很好的讨论。考虑以下几点:

  • 如果你说免费(p + 1)会被归零吗?
  • 如果内存有两个指针怎么办?如果悬空参考仍然留下,为什么只将一个设置为null?

他还说这是有意的,但从未发生在operator delete

C ++明确允许delete的实现将左值操作数归零,我曾希望实现会这样做,但这个想法似乎并没有受到实现者的欢迎。

答案 3 :(得分:7)

C函数参数总是按值传递,因此为了修改传递给free()的指针,您需要将指针传递给被释放的指针,这可能会导致忘记&amp;运算符。

其次,如果该指针有任何别名,程序员仍然负责将它们输出。我可以看到程序员假设所有引用都设置为NULL所引起的问题。

最后,并不总是需要将指针设置为NULL。想象一个函数,它分配一些内存,做一些工作并在返回之前释放它。我可以看到如何将指针设置为NULL似乎不是最佳的。

答案 4 :(得分:5)

因为函数参数是用C中的值传递的。也就是说,如果p == 0x12345,你将'0x12345'传递给free(),而不是p“本身”。

答案 5 :(得分:2)

在C中,调用函数永远不会改变传入的参数的值,因此如果free(p)通过将p设置为NULL来改变{{1}}的值,那么此行为将会确实非常不标准。

答案 6 :(得分:2)

参考Stroustrup关于删除的引用,Peter Norvig也发表了类似的评论。他写道(不是关于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))

在我的C代码中,我发现以下宏非常有用:

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

正如所写的那样,它使用了两次参数。但这不是问题,因为任何用法(例如free(p ++)或free(find_named_object(“foo”))都会产生编译时错误(需要左值)。你可以通过使用(免费)(p ++)或通过调用其他内容来隐藏宏,例如FREE。

答案 7 :(得分:0)

将引用从int *&转换为void *& 保证可以正常工作。 int *根本不必具有与void *相同的大小,表示形式和对齐要求。

正确的C ++解决方案将是使用模板,正如Neil Butterworth在评论中所建议的那样。这些方式都不适用于C,显然 - free()来自哪里。

答案 8 :(得分:0)

零的疯狂之处是什么?还有其他数字!

为什么自由指针应该包含多于零的任何其他值?

实际上,在我的C ++代码中,我经常使用看门狗对象,当释放指针时,将其重置为零而不是看门狗。这有一个额外的好处,即仍然可以使用现有接口调用对象的方法,并且将指针重置为零更安全有效(它避免将对象测试为零,我只是调用对象)。

如果一个自由的函数说zfree(void *&amp; p)将p设置为零,那么它将禁止我的看门狗风格(或者至少不会有帮助)。

正如其他人指出的那样,如果指针超出范围,将指针重置为零会有什么意义?只是没用的代码。如果有其他指针包含相同的地址,等等。