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


127

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

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

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

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

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

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

Ответы:


150

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

C ++ явно допускает реализацию delete для обнуления операнда lvalue, и я надеялся, что реализации это сделают, но эта идея, похоже, не стала популярной среди разработчиков.

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


Я думаю, здесь нужно еще какое-то объяснение. Я даже не уверен, что он говорит ... Полагаю, мне придется вернуться позже, когда я смогу посвятить пару часов исследованию этого, пока я не получу это. Или вы можете разъяснить ответ, чтобы помочь нам быстрее понять.
Габриэль Стейплс

63

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

Затем идет перформанс. Вы могли написать код таким образом, чтобы указатель выходил за пределы области действия сразу после удаления . Заполнение его нулевым значением - пустая трата времени. А C ++ - это язык с идеологией «не нужно? Тогда за это не нужно платить».

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


4
Хороший момент по отношению к рассчитанному адресу, даже если вы его не часто видите
марш

Вы говорите о новом размещении, когда говорите, что иногда вы можете захотеть удалить объект по только что рассчитанному адресу. ???
Деструктор

@PravasiMeet Нет, я имею в виду что-то вродеdelete (ptr + i)
sharptooth

39

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


19

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

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

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

12

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


правда, но это приведет к тем же накладным расходам,
марш

7

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

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

T* const foo = new T;
delete foo;

6

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

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

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


5

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


4

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


4

Философия C ++ - «плати, только если пользуешься». Думаю, это может ответить на ваш вопрос.

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


3

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


-1

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

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.