Почему не освобождает (p) значение p до NULL?

Любые причины, по которым это не может быть стандартным поведением 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*& (ссылка)

Ответы

Ответ 1

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

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

который, я уверен, многие люди ошибаются.

Ответ 2

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

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

Ответ 3

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

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

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

С++ явно позволяет реализовать delete, чтобы обнулить операнд lvalue, и я надеялся, что реализация будет делать это, но эта идея, похоже, не стала популярной среди разработчиков.

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

Ссылаясь на цитату из Страуступа об исключении, Питер Норвиг также делает аналогичное замечание. Он пишет (не о С++!):

"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 ++), или, называя его чем-то другим, например. БЕСПЛАТНО.

Ответ 7

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

Ответ 8

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

Правильное решение на С++ предназначено для использования шаблонов, как предлагает Neil Butterworth в комментарии. И ни один из этих способов не работает на C, очевидно, откуда приходит free().

Ответ 9

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

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

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

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

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