Почему delete не устанавливает указатель на NULL?

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

  1. производительность:

    дополнительная инструкция может замедлить delete производительность.

  2. может быть, это из-за const указатели.

    потом опять стандарт мог бы сделать что-то для этого особого случая, я думаю.

кто-нибудь знает точные причины, по которым это не разрешено?

12 ответов


Страуструп ответы. Отрывок:

C++ явно разрешает реализация delete to zero out операнд lvalue, и я надеялся что реализации будут делать это, но эта идея, кажется, не имеют станьте популярными у исполнителей.

но основная проблема, которую он поднимает, заключается в том, что аргумент delete не должен быть lvalue.


во-первых, для установки значения null потребуется переменная, хранящаяся в памяти. Это правда, что у вас обычно есть указатель в переменной, но иногда вы можете захотеть удалить объект по только что вычисленному адресу. Это было бы невозможно, если исключить слово "аннулирование".

затем идет производительность. Возможно, вы написали код таким образом, что указатель выйдет из области действия сразу после удалить сделано. Заполнение его 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, когда память будет освобождена. Если вы хотите, чтобы он был нулевым.. напишите ему null:)


C++ позволяет вам определить свой собственный оператор new и delete, чтобы, например, они использовали ваш собственный распределитель пула. Если вы это сделаете, можно использовать new и delete с вещами, которые не являются строго адресами, но говорят индексы в вашем массиве пула. В этом контексте значение NULL (0) может иметь юридическое значение (ссылаясь на первый элемент в пуле).
Таким образом, удаление значения NULL автоматически в его аргумент не всегда имеет значение-установить значение неверное значение. Недопустимое значение не всегда может быть NULL.


вот еще одна причина; предположим, что delete устанавливает свой аргумент в NULL:

int *foo = new int;
int *bar = foo;
delete foo;

должен ли bar получить значение NULL? Можете ли вы обобщить это?


философия C++ - "платить за него, только если вы его используете". Думаю, это ответ на ваш вопрос.

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


установка указателя на NULL автоматически не решит большинство проблем с плохим использованием указателя. Единственный сбой, которого он избежит, - это если вы попытаетесь удалить его дважды. Что делать, если вы вызываете функцию-член на таком указателе? Он по-прежнему будет сбой (при условии, что он обращается к переменным-членам). C++ не ограничивает вас от вызова любой функции на нулевых указателях, и не должен делать это с точки зрения производительности.


Я вижу, что люди дают странные ответы на этот вопрос.

ptr = NULL; Как такое простое утверждение может вызвать задержку производительности?

другой ответ говорит, что мы можем иметь несколько указателей, указывающих на тот же ячейка памяти. Конечно, можем. В этом случае операция удаления одного указателя сделает только этот указатель нулевым (если delete делает указатель нулевым) , а другой указатель будет ненулевым и указывает на местоположение памяти, которое бесплатный.

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

Stroustrup мог бы разработать delete для работы таким образом. Он думал, что программисты позаботятся об этом. Поэтому он проигнорировал.