Почему не удалить установить указатель на NULL?
Я всегда задавался вопросом, почему автоматическая установка указателя на NULL после удалить не является частью стандарта. Если об этом позаботятся, то многие сбои из-за недопустимого указателя не возникнут. Но сказав, что я могу придумать пару причин, почему стандарт ограничил бы это:
производительность:
дополнительная инструкция может замедлить
delete
производительность.может быть, это из-за
const
указатели.потом опять стандарт мог бы сделать что-то для этого особого случая, я думаю.
кто-нибудь знает точные причины, чтобы не допустить этого?
12 ответов:
Страуструп ответы. Отрывок:
C++ явно позволяет реализация удаления до нуля операнд lvalue, и я надеялся что реализации будут делать это, но эта идея, похоже, не имеет станьте популярным среди исполнителей.
но главная проблема, которую он поднимает, заключается в том, что аргумент delete не должен быть lvalue.
во-первых, для установки значения null потребуется переменная, хранящаяся в памяти. Это правда, что у вас обычно есть указатель в переменной, но иногда вы можете захотеть удалить объект по только что вычисленному адресу. Это было бы невозможно с "аннулированием" удаления.
затем идет производительность. Возможно, вы написали код таким образом, что указатель выйдет из области действия сразу после удалить сделано. Заполнение его нулем - это просто пустая трата времени. И C++ - это язык с "не нужен? тогда вам не придется за это платить".
Если вам нужна безопасность, то широкий диапазон умных указателей на вас обслуживает или вы можете написать ваше собственное-лучше и умнее.
вы можете иметь несколько указателей, указывающих на память. Это создало бы ложное чувство безопасности, если указатель, указанный для удаления, получил значение null, но все остальные указатели этого не сделали. Указатель-это не что иное, как адрес, число. Это также может быть int с операцией разыменования. Я хочу сказать, что вам также придется сканировать каждый указатель, чтобы найти те, которые ссылаются на ту же память, которую вы только что удалили, и обнулить их. Было бы вычислительно интенсивно сканировать все указатели для этого адреса и обнулять их, потому что язык не предназначен для этого. (Хотя некоторые другие языки структурируют свои ссылки для достижения аналогичной цели по-другому.)
указатель может быть сохранен в нескольких переменных, установка одного из них в NULL все равно оставит недопустимые указатели в других переменных. Таким образом, вы на самом деле не получаете много, вы, скорее всего, создаете ложное чувство безопасности.
кроме того, вы можете создать свою собственную функцию, которая делает то, что вы хотите:
template<typename T> void deleten(T *&ptr) { delete ptr; ptr = NULL; }
потому что на самом деле нет никакой необходимости, и потому что для этого потребуется удалить указатель на указатель, а не просто указатель.
delete
используется в основном в деструкторах, и в этом случае установка элемента в NULL бессмысленна. Через несколько строк, в конце}
, элемент больше не существует. В операторах присваивания удаление обычно сопровождается присвоением в любом случае.кроме того, это сделало бы следующий код незаконным:
T* const foo = new T; delete foo;
Если у вас есть массив указателей, и ваше второе действие-удалить пустой массив, то нет никакого смысла устанавливать каждое значение null, когда память будет освобождена. Если вы хотите, чтобы он был нулевым.. пишут нуль, к нему :)
C++ позволяет определить свой собственный оператор new и delete, чтобы, например, они использовали свой собственный распределитель пула. Если вы сделаете это, то можно использовать new и delete с вещами, которые не являются строго адресами, но говорят индексы в вашем массиве пула. В этом контексте значение NULL (0) может иметь юридическое значение (ссылаясь на первый элемент в пуле).
Таким образом, удаление набора NULL автоматически для его аргумента не всегда имеет значение - установите значение в значение неверное значение. Недопустимое значение не всегда может быть NULL.
вот еще одна причина; предположим, что delete устанавливает свой аргумент в NULL:
int *foo = new int; int *bar = foo; delete foo;
должен ли бар получить значение NULL? Можете ли вы обобщить это?
философия C++- это "платить за него, только если вы его используете". Я думаю, что это может ответить на ваш вопрос.
также иногда вы можете иметь свою собственную кучу, которая будет восстанавливать удаленную память.. или иногда указатель не принадлежит какой-либо переменной. Или указатель хранится в нескольких переменных - возможно ноль только одной из них.
Как вы можете видеть есть много вопросов и возможных проблем.
установка указателя на NULL автоматически не решит большинство проблем с плохим использованием указателя. Единственный сбой, которого он избежит, - это если вы попытаетесь удалить его дважды. Что делать, если вы вызываете функцию-член на такой указатель? Он все равно аварийно завершит работу (при условии, что он обращается к переменным-членам). C++ не ограничивает вас от вызова любой функции на нулевые указатели, и он не должен делать это с точки зрения производительности.
Я вижу, что люди дают странные ответы на этот вопрос.
ptr = NULL; Как такое простое утверждение может вызвать задержку производительности?
другой ответ говорит, что мы можем иметь несколько указателей, указывающих на тот же ячейка памяти. Конечно, можем. В этом случае операция удаления одного указателя сделает только этот указатель NULL (если delete делает указатель NULL) , а другой указатель будет ненулевым и указывающим на ячейку памяти, которая является бесплатный.
решение для этого должно было заключаться в том, что пользователь должен удалить все указатели, указывающие на одно и то же место. Внутренне он должен проверить, если память уже освобождена, чем не бесплатно. Только сделайте указатель нулевым.
Stroustrup мог бы разработать delete для работы таким образом. Он думал, что программисты позаботятся об этом. Поэтому он проигнорировал.