Я помню, где-то читал, что это необходимо для delete NULL
быть допустимой операцией в C ++, но я не могу вспомнить причину, почему это должно быть так. Кто-нибудь, пожалуйста, напомните мне?
Правило не является строго необходимым в том, что язык мог существовать без него; это просто решение, принятое комитетом по стандартам. Нулевой указатель не является допустимым адресом памяти. Тем не менее, я хотел бы верить, что каждое решение принимается по определенной причине, и эти причины стоит знать.
Это правило упрощает управление случаями сбоя и другими случаями, в которых указатель может быть нулевым. Это простая, недорогая проверка, и она добавляет заметное удобство для языка.
Например, если существует много условий, которые могут привести к динамическому распределению памяти, но существуют и другие, которых не будет, удобно иметь возможность просто придерживаться delete
в конце и не переживай.
// contrived example
void foo(int n) {
char *p = nullptr;
switch(n) {
case whatever:
case something_else:
p = new char[n];
break;
}
// some code...
delete [] p; // look Ma, no check!
}
Если delete nullptr
были незаконны, то каждый звонок delete
будет окружен …
if(ptr)
…и это было бы хромым. Поскольку это было бы нормой, по сути обязательным соглашением, почему бы просто не исключить необходимость полной проверки? Зачем требовать дополнительные 5 символов (минимум) для каждого вызова delete
?
Точная причина:
Возможная причина:
delete
в коде пользователя.Прежде всего, NULL
никогда не является допустимым значением указателя (в размещенной программе C ++), и поэтому нет никакой двусмысленности относительно того, указывает ли указатель на живой объект или нет. Во-вторых, логика управления внутренней памятью должна в любом случае выполнять свою собственную проверку, чтобы вести бухгалтерию, поэтому, по-видимому, ничего не будет получено от того, чтобы указатель был ненулевым.
Итак, теперь мы знаем, что ничего не говорит против это правило, вот большой аргумент в его пользу: это значительно облегчает написание кода. Рассмотрим этот простой фрагмент обработки кода выделения:
T * p1 = NULL;
T * p2 = NULL;
T * p3 = NULL;
try
{
p1 = new T;
p2 = new T;
p3 = new T;
}
catch (...)
{
delete p1;
delete p2;
delete p3;
throw;
}
Это просто и беспорядочно. Если бы нам нужно было добавлять NULL-проверки везде, это сделало бы код намного менее читаемым и затенило логику кода.
Потому что Комитет по Стандартам знает, что нет программа может иметь NULL для указания на допустимый объект, т.е. NULL не может указывать на действительную память, поэтому запись безопасна delete NULL
именно потому, что это не на самом деле удалить что-нибудь. Так как это безопасно, то это избавляет вас от необходимости проверять NULL, прежде чем delete
:
//if (ptr != NULL) NOT NEEDED
delete ptr; //safe even if ptr == NULL
Потому что разработчик библиотеки просто должен написать if (ptr == nullptr) return;
один раз. Вы, пользователь, должны были бы написать это 9999999999 раз по всей вашей программе. Таким образом, это простой случай, который делает это внутри delete
намного проще.
Удаление нулевого указателя не имеет никакого эффекта (если функция освобождения указана в стандартной библиотеке [2]), поэтому нет необходимости проверять нулевой указатель перед вызовом delete.
также проверьте Безопасно ли удалять нулевой указатель? это может помочь вам
Ну, я хорошо помню, что правила удаления указателя наconst
(теперь все в порядке) изменилось со стандартизацией, то есть они отличались в ARM, Аннотированном справочном руководстве.
Но я не уверен насчет удаления 0; Я думаю, что это всегда поддерживалось.
Во всяком случае, это просто о удобство, для операции, где стоимость проверки незначительна и где она может / вероятно может быть выполнена компилятором более эффективно, чем какой-либо определенной пользователем функцией-оболочкой для удаления.