2009-09-17 74 views
3

如何通过使用免费名称编写包装函数来解决双重空闲问题,以便我不需要更改源代码中的每个免费呼叫?双免费问题

+0

相关:http://stackoverflow.com/questions/678254/c-function-conflict – dmckee 2009-09-17 15:04:44

+0

也相关:http://stackoverflow.com/questions/617554/override-a-function-call-in-c – dreamlax 2009-09-18 09:25:25

+0

对不起,在那里吹着我自己的号角 – dreamlax 2009-09-18 09:26:04

回答

8

不要做

一个简单的方法是定义你的包装功能和#定义自由打电话给你的函数。

#undef free 
#define free(x) wrapper_free(x) 
/* ... */ 
int *data = malloc(42); 
free(data); /* effectively calls wrapper_free(data) */ 

但是...... 不这样做!

+2

您应将defenition之前做一个'和#undef free':标准C允许STDLIB功能进行的方法,另外作为宏 – Christoph 2009-09-17 14:59:53

+0

@pmg实现你能解释一下为什么不呢? – Gewure 2017-03-14 13:52:56

+1

@gewure:'free()'有一个非常精确的定义。从长远来看,用别的东西代替它肯定会伤害到你(你会比你想象的更快地忘记替换)。尤其如果您在头文件中提供“重定义”。 – pmg 2017-03-14 17:01:20

28

不要这样做。

不,真的。修复实际问题。一旦在指针上调用了空闲()之后,代码应该由而不是由于任何原因持有它。将它清空,所以你不能再释放它;这将会导致由stale指针解引用导致的任何其他问题也可见。

+6

+1将指针设置为NULL。这实际上是最简单的解决方案,永远不会双倍免费。无论如何,编写一个执行'free()'的自定义'my_free()',然后将指针设置为NULL似乎是确保这一点的最简单方法。但是,这涉及代码更改:-) – Joey 2009-09-17 14:31:25

+0

关于包装器functino的好处,它负责将指针归零。有些语言甚至包含这些内容,而使用它们总是一个好习惯。 Delphi对象有一个free()方法,但最好使用FreeAndNil()全局函数。当指针已经为空时,它也不会抛出错误。 – 2009-09-17 14:39:52

+9

@Chris:是什么让你认为'free(NULL)'引发错误? ANSI标准,第4.10.3.2节:“如果ptr是空指针,则不会发生任何操作。” – Christoph 2009-09-17 14:50:24

1

我同意其他职位说,你不应该。主要的是,让人们看看你的代码并试图弄清楚发生了什么(当他们习惯于只看到释放内存的空闲时)会更困惑。

如果你正在寻找一行代码,可以让你释放和清除指针,我建议使用一个宏,尽管还有其他方法来做到这一点(创建一个方法,需要一个指针指向你的指针)。

#define FREEANDCLEAR(pointer)\ 
{\ 
    free(pointer);\ 
    pointer = 0;\ 
} 

编辑 作为克里斯托弗在评论中提到,你也可以确保用户使用宏像一个函数(用做结尾用分号线,而像这样:

#define FREEANDCLEAR(pointer)\ 
do {\ 
    free(pointer);\ 
    pointer = 0;\ 
} while(0) 

将执行一次,并要求结束分号。

+2

没有必要检查'if(pointer)'''free(NULL)'是否有效并且什么也不做;此外,您可能想在'do..while与包装这个()'循环来获取函数的语法 – Christoph 2009-09-17 14:42:13

+0

感谢克里斯托弗,我如果取消了,用在DO增加了第二个实现! – 2009-09-17 15:10:57

0

去翻答案,计算器问题,"Write your own memory manager"

在这些答案中使用这些工具或技术将允许您使用内存管理器来检查这些类型的问题,以便您可以识别并修复这些问题(对于您的问题,许多其他答案表明,使用某些东西并不是一个好主意像这是一个解决方法)。

7

以下代码截取对malloc()realloc()calloc()进行日志记录的调用。

当调用free()时,它检查内存是否被预先分配了其中一个函数。否则,程序将被终止。释放空指针将被报告,但执行将继续。

页眉memdebug.h

#undef free 
#define free(PTR) memdebug_free(PTR, #PTR, __FILE__, __func__, __LINE__) 

#undef malloc 
#define malloc(SIZE) memdebug_log(malloc(SIZE)) 

#undef realloc 
#define realloc(PTR, SIZE) memdebug_log(realloc(PTR, SIZE)) 

#undef calloc 
#define calloc(COUNT, SIZE) memdebug_log(calloc(COUNT, SIZE)) 

#ifndef MEMDEBUG_H 
#define MEMDEBUG_H 

extern void memdebug_free(void *ptr, const char *ptr_arg, const char *file, 
    const char *func, int line); 
extern void *memdebug_log(void *ptr); 

#endif 

来源memdebug.c

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

#ifndef MEMDEBUG_TABLE_SIZE 
// log 16k allocations by default 
#define MEMDEBUG_TABLE_SIZE 0x4000 
#endif 

static void *alloc_table[MEMDEBUG_TABLE_SIZE]; 
static size_t top; 

void *memdebug_log(void *ptr) 
{ 
    assert(top < sizeof alloc_table/sizeof *alloc_table); 
    alloc_table[top++] = ptr; 
    return ptr; 
} 

void memdebug_free(void *ptr, const char *ptr_arg, const char *file, 
    const char *func, int line) 
{ 
    if(!ptr) 
    { 
     fprintf(stderr, 
      "%s() in %s, line %i: freeing null pointer `%s` -->continue\n", 
      func, file, line, ptr_arg); 

     return; 
    } 

    for(size_t i = top; i--;) 
    { 
     if(ptr == alloc_table[i]) 
     { 
      free(ptr); 
      --top; 
      if(i != top) alloc_table[i] = alloc_table[top]; 
      return; 
     } 
    } 

    fprintf(stderr, 
     "%s() in %s, line %i: freeing invalid pointer `%s`-->exit\n", 
     func, file, line, ptr_arg); 

    exit(EXIT_FAILURE); 
} 
+0

+1,这应该适用于嵌入式环境或valgrind不可用时的其他情况。 – 2009-09-17 23:22:25

1

除了所有其他的答案和参考内存管理的研究与开发等。

当双自由存在这样的指示,事情并没有按照正确的顺序完成的代码等错误发生

当我大约10年前开始使用Java,大家都称赞Java的,因为你没有不得不烦扰新/删除。

我很困扰(因为我是用C/C++开发的),因为除了malloc/free之外,突然间所有的open/close,create/destroy,锁定/解锁模式都以多种方式出现可能会被打破,因为大家都认为所有清理都是自动的。

所以当你有这些问题,你可能有其他的问题迟早的事。资源不足,数据库连接被占用,文件锁定在文件系统上。

双人自由是你的程序不具有良好的结构的信号,被分配在一个层e.g的事情,而在另一个释放。