15

为什么这不能成为标准行为的任何原因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*&(参考)

4

9 回答 9

28

如果是这样,则必须将指针传递给指向函数的指针:

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

我敢肯定很多人会弄错。

于 2010-04-16T09:37:33.133 回答
27

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

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

于 2010-04-16T09:35:32.263 回答
15

Bjarne Stroustrup讨论delete运算符是否应将其操作数归零。这不是 free() 函数,但无论如何这是一个很好的讨论。考虑以下几点:

  • 如果你说 free(p + 1),什么会归零?
  • 如果有两个指向内存的指针怎么办?如果仍然留下悬空引用,为什么只将一个设置为 null ?

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

C++ 明确允许删除的实现将左值操作数清零,我曾希望实现能够做到这一点,但这个想法似乎并没有在实现者中流行。
于 2010-04-16T10:35:16.227 回答
6

C 函数参数始终按值传递,因此为了修改传递给 free() 的指针,您需要将指针传递给正在释放的指针,这可能会导致忘记 & 运算符引起的错误。

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

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

于 2010-04-16T09:50:00.943 回答
5

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

于 2010-04-16T09:37:48.247 回答
2

在 C 中,调用函数永远不能改变你传入的参数的值,所以如果通过设置它来free(p)改变值,那么这种行为确实是非常不标准的。pNULL

于 2010-04-16T09:38:41.293 回答
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")) 都会产生编译时错误(需要左值)。您可以通过使用 (free)(p++) 或将其称为其他名称(例如 FREE)来隐藏宏。

于 2010-04-16T17:21:24.037 回答
0

零这个疯狂的东西是什么?还有其他数字!

为什么自由指针应该比任何其他可区分值包含更多零?

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

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

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

于 2010-07-13T11:18:46.323 回答
0

保证 将引用从int *&to 转换void *&为有效。根本不必具有与.int *void *

正如 Neil Butterworth 在评论中建议的那样,正确的 C++ 解决方案是使用模板。显然,这些方式在 C 中都不起作用——这就是它的free()来源。

于 2010-04-16T23:37:27.810 回答