Ответ 1
Если бы это было так, вам нужно было бы передать указатель на указатель на функцию:
int * p = malloc( sizeof( int ));
free( & p );
который, я уверен, многие люди ошибаются.
Любые причины, по которым это не может быть стандартным поведением 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*&
(ссылка)
Если бы это было так, вам нужно было бы передать указатель на указатель на функцию:
int * p = malloc( sizeof( int ));
free( & p );
который, я уверен, многие люди ошибаются.
Простой ответ: потому что вы можете освободить выражение, например. free(find_named_object("foo"))
.
Более подробно: функция free
принимает параметр void*
, который является адресом свободной памяти. Это не дает функции любому знанию исходной переменной, которая указала адрес (или, если на то пошло, существует ли даже переменная). Просто установка параметра, переданного в NULL, тоже ничего не сделает, поскольку это просто локальная копия адреса.
Bjarne Stroustrup обсуждает, должен ли оператор delete
обнулить операнд. Это не функция free(), но в любом случае это хорошая дискуссия. Рассмотрим такие моменты, как:
Он также говорит, что он был предназначен, но никогда не случался с operator delete
:
С++ явно позволяет реализовать delete, чтобы обнулить операнд lvalue, и я надеялся, что реализация будет делать это, но эта идея, похоже, не стала популярной среди разработчиков.
Параметры функции C всегда передаются по значению, поэтому для изменения указателя, переданного в free(), вам нужно будет передать указатель на освобожденный указатель, что может привести к ошибкам, вызванным забытыми и операторами.
Во-вторых, если у этого указателя были какие-либо псевдонимы, программист все равно будет нести ответственность за их обнуление. Я мог видеть проблемы, вызванные программистами, предполагающими, что для всех ссылок задано значение NULL.
Наконец, не всегда необходимо установить указатель в NULL. Представьте себе функцию, которая выделяет некоторую память, выполняет некоторую работу и освобождает ее перед возвратом. Я видел, как настройка указателя на NULL может показаться не оптимальной.
Поскольку параметры функции передаются по значению в C. То есть, если p == 0x12345 вы передаете '0x12345' на free(), а не p "самостоятельно".
Ссылаясь на цитату из Страуступа об исключении, Питер Норвиг также делает аналогичное замечание. Он пишет (не о С++!):
"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 ++), или, называя его чем-то другим, например. БЕСПЛАТНО.
В C вызов функции никогда не может изменить значение параметров, которые вы передаете, поэтому, если free(p)
изменило значение p
, установив его на NULL
, тогда это поведение было бы очень нестандартным.
Выполнение задания с int *&
до void *&
гарантировано не. int *
просто не должен иметь одинаковые требования к размеру, представлению или выравниванию в качестве void *
.
Правильное решение на С++ предназначено для использования шаблонов, как предлагает Neil Butterworth в комментарии. И ни один из этих способов не работает на C, очевидно, откуда приходит free()
.
Что это за маньяка с нулем? Есть и другие номера!
Почему бесплатный указатель должен содержать ноль больше любого другого выделенного значения?
Практически, в моем коде на С++ я часто использую объекты сторожевого таймера и освобождая указатель reset, он не равен нулю, а сторожевому таймеру. Это имеет дополнительное преимущество в том, что методы объекта все еще могут быть вызваны с помощью существующего интерфейса и намного более безопасны и эффективны, чтобы сбросить указатель на нуль (чтобы избежать проверки объектов на ноль, я просто вызываю объект).
Если свободная подобная функция говорит, что zfree (void * и p) установит p в ноль, это запретит мой стиль сторожевого таймера (или, по крайней мере, не поможет).
И как другие указатели, какая точка для reset указатель на ноль, если он выходит за пределы области видимости? Просто бесполезный код. И что, если есть другие указатели, содержащие один и тот же адрес и т.д.