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