Почему не удалить установить указатель на NULL? - PullRequest
118 голосов
/ 01 апреля 2009

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

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

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

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

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

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

Ответы [ 12 ]

145 голосов
/ 01 апреля 2009

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

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

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

59 голосов
/ 01 апреля 2009

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

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

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

36 голосов
/ 01 апреля 2009

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

18 голосов
/ 01 апреля 2009

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

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

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}
12 голосов
/ 01 апреля 2009

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

7 голосов
/ 02 апреля 2009

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

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

T* const foo = new T;
delete foo;
5 голосов
/ 01 октября 2010

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

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

Должен ли бар иметь значение NULL? Вы можете обобщить это?

5 голосов
/ 01 апреля 2009

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

4 голосов
/ 01 апреля 2009

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

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

4 голосов
/ 01 апреля 2009

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

...