Почему free (p) не устанавливает p в NULL? - PullRequest
16 голосов
/ 16 апреля 2010

Какие-либо причины, почему это не может быть стандартным поведением 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 ]

28 голосов
/ 16 апреля 2010

Если это так, вам нужно будет передать указатель на указатель на функцию:

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

что, я уверен, многие ошибаются.

27 голосов
/ 16 апреля 2010

Простой ответ: потому что вы можете освобождать выражение, например, free(find_named_object("foo")).

Более подробно: функция free принимает параметр void*, который является адресом свободной памяти. Это не дает функции никакого знания об исходной переменной, которая предоставляла адрес (или, в этом отношении, существует ли вообще переменная). Установка параметра, переданного в NULL, также ничего не изменит, поскольку это просто локальная копия адреса.

15 голосов
/ 16 апреля 2010

Бьярне Страуструп обсуждает, должен ли оператор delete обнулять свой операнд . Это не функция free (), но в любом случае это хорошее обсуждение. Рассмотрим такие моменты, как:

  • Что бы обнулить, если бы вы сказали free (p + 1)?
  • Что если в памяти есть два указателя? Зачем устанавливать значение NULL только в том случае, если висячая ссылка все еще остается позади?

Он также говорит, что это было задумано, но никогда не случалось с operator delete:

C ++ явно разрешает реализацию delete для обнуления операнда lvalue, и я надеялся, что реализации сделают это, но эта идея, похоже, не стала популярной среди разработчиков.
7 голосов
/ 16 апреля 2010

Параметры функции C всегда передаются по значению, поэтому для изменения указателя, переданного free (), вам необходимо передать указатель на освобождаемый указатель, что может привести к ошибкам, вызванным забытыми операторами &.

Во-вторых, если бы у этого указателя были псевдонимы, программист все равно отвечал бы за обнуление их . Я мог видеть проблемы, вызванные программистами, предполагавшими, что все ссылки были установлены в NULL.

Наконец, не всегда необходимо устанавливать указатель в NULL. Представьте себе функцию, которая выделяет некоторую память, выполняет некоторую работу и освобождает ее перед возвратом. Я видел, как установка указателя на NULL может показаться неоптимальной.

5 голосов
/ 16 апреля 2010

Поскольку параметры функции передаются по значению в C. То есть, если p == 0x12345, вы передаете '0x12345' free (), а не p "себе".

2 голосов
/ 16 апреля 2010

Ссылаясь на цитату из Страуструпа об удалении, Питер Норвиг также делает подобное замечание. Он пишет (не о 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")), приведет к ошибке времени компиляции (требуется lvalue). И вы можете скрыть макрос, используя (бесплатно) (p ++) или называя его как-нибудь еще, например. БЕСПЛАТНО.

2 голосов
/ 16 апреля 2010

В C, вызов функции никогда не может изменить значение параметров, которые вы передаете, поэтому, если free(p) изменил значение p, установив его на NULL, то это поведение было бы действительно очень нестандартным .

0 голосов
/ 13 июля 2010

Что это за маньяк с нуля? Есть и другие номера!

Почему свободный указатель должен содержать ноль больше, чем любое другое выделенное значение?

Практически, в моем коде C ++ я часто использую сторожевые объекты и при освобождении указателя сбрасываю его не в ноль, а в сторожевой таймер. Это дает дополнительное преимущество, заключающееся в том, что методы объекта могут по-прежнему вызываться с существующим интерфейсом, и это намного более безопасно и эффективно, чем сброс указателя на ноль (это позволяет избежать проверки объектов на ноль, я просто называю объект).

Если бы функция free like, скажем, zfree (void * & p) установила бы p на ноль, это запретило бы мой сторожевой стиль (или, по крайней мере, не помогло бы).

И как указывают другие, какой смысл сбрасывать указатель на ноль, если он выходит из области видимости? Просто бесполезный код. А что, если есть другие указатели, содержащие тот же адрес и т. Д.

0 голосов
/ 17 апреля 2010

Приведение ссылки от int *& к void *& - это , а не гарантированно работает. int * просто не должен иметь такие же требования к размеру, представлению или выравниванию, как void *.

Правильным решением на C ++ было бы использование шаблонов, как предполагает Нил Баттерворт в комментарии. И ни один из этих способов не работает в C, очевидно - отсюда free().

...