Итак, я придумал хороший пример двойного указателя на пустоту (то есть void**
).Один из способов сократить количество ошибок, не связанных с двойной ошибкой, - это всегда устанавливать указатели в NULL после их освобождения.
Мы можем сделать это так (сомнительный стиль):
myprojectinclude.h:
/* must happen after any standard headers */
void freep(void **pointer);
#define free(p) error_call_freep_instead p /* so that free doesn't exist anymore */
freep.c:
#include <stdlib.h>
#include "myprojectinclude.h"
#undef free
void freep(void **p)
{
if (p) {
free(*p);
*p = NULL;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "myprojectinclude.h"
int main()
{
char *buffer = malloc(2048);
size_t buffer_size = 2048;
/* ... lots of code involving reading lines, etc. */
freep(&buffer);
/* buffer is guaranteed to be NULL here */
}
При такой настройке двойное освобождение невозможно.Если мы сделаем
freep(&buffer);
freep(&buffer);
, все пойдет не так, потому что buffer
равен NULL после первого вызова.(Обратите внимание, что передача NULL в free безопасна; иначе мы добавили бы проверку NULL, как я это делал десятилетия назад.)