Почему не удаляет указатель на NULL?

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

  • Производительность:

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

  • Это может быть из-за указателей const.

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

Кто-нибудь знает точные причины не допускать этого?

Ответы

Ответ 1

Отвечает сам Страуструп. Выдержка:

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

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

Ответ 2

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

Затем идет производительность. Возможно, вы написали код таким образом, чтобы указатель выходил за пределы области сразу после удаления. Заполнение его нулем - это пустая трата времени. И С++ - это язык с идеей "не нужно, то вам не нужно платить за это".

Если вам нужна безопасность, вам предоставляется широкий спектр интеллектуальных указателей, или вы можете написать свой собственный - лучше и умнее.

Ответ 3

У вас может быть несколько указателей, указывающих на эту память. Это создало бы ложное чувство безопасности, если указатель, указанный вами для удаления, получил значение null, но все остальные указатели этого не сделали. Указатель - это не что иное, как адрес, число. Это также может быть int с операцией разыменования. Я хочу сказать, что вам придется также сканировать каждый указатель, чтобы найти те, которые ссылаются на одну и ту же память, которую вы только что удалили, и также обнулить их. Было бы сложно вычислить интенсивность сканирования всех указателей для этого адреса и обнулить их, потому что язык не предназначен для этого. (Хотя некоторые другие языки структурируют свои ссылки для достижения аналогичной цели по-другому.)

Ответ 4

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

Кроме того, вы можете создать свою собственную функцию, которая делает то, что вы хотите:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

Ответ 5

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

Ответ 6

delete используется в основном в деструкторах, и в этом случае установка члена в NULL бессмысленна. Несколько строк позже, при закрытии }, член больше не существует. В операциях присваивания в любом случае обычно выполняется удаление.

Кроме того, это сделает следующий код незаконным:

T* const foo = new T;
delete foo;

Ответ 7

Если у вас есть массив указателей, а второе действие - удаление пустого массива, то нет смысла устанавливать значение каждого значения равным нулю, когда память будет освобождена. Если вы хотите, чтобы это было null.. напишите null к нему:)

Ответ 8

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

Ответ 9

Философия С++ - это "платить за нее, только если вы ее используете". Я думаю, это может ответить на ваш вопрос.

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

Ответ 10

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

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

Должен ли бар установить значение NULL? Можете ли вы обобщить это?

Ответ 11

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

Ответ 12

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

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

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

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

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