Проверка NULL перед удалением объекта с перегруженным удалением - PullRequest
26 голосов
/ 29 сентября 2010

Это прозвучало как один из комментариев к коду.

Хорошая ли идея проверить NULL перед вызовом delete для какого-либо объекта?

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

Ответы [ 11 ]

35 голосов
/ 29 сентября 2010

Нет, не проверять на ноль.Стандарт гласит, что delete (T*)0; действует.Это просто усложнит ваш код без каких-либо преимуществ.Если operator delete перегружен, то лучше проверять на нуль в реализации оператора.Просто сохраняет строки кода и ошибки.

РЕДАКТИРОВАТЬ: Этот ответ был принят и проголосовал, но, на мой взгляд, он был не очень информативным.Здесь есть один недостающий фрагмент во всех ответах, и, ради совести, позвольте мне добавить этот последний фрагмент здесь.

Стандарт фактически говорит в [basic.stc.dynamic], по крайней мере, начиная с C ++ 03:

Любые функции выделения и / или освобождения, определенные в программе на C ++, включая версии по умолчанию в библиотеке, должны соответствовать семантике, указанной в 3.7.4.1 и 3.7.4.2.

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

19 голосов
/ 29 сентября 2010

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

7 голосов
/ 29 сентября 2010

Стоит ли проверять NULL перед вызовом delete для какого-либо объекта?

Нет!

int *p = NULL;
delete p ; //no effect

Стандарт гласит [Раздел 5.3.5 / 2]

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

Кроме того, в разделе 18.4.1.1/13

void operator delete(void* ptr) throw();

void operator delete(void* ptr, const std::nothrow_t&) throw();

Поведение по умолчанию:

- При нулевом значении ptr ничего не делать .

- Любое другое значение ptr должно быть значением, возвращенным ранее вызовом оператора по умолчанию new, который не был аннулирован промежуточным вызовом оператора delete (void *) (17.4.3.7). Для такого ненулевого значения ptr освобождает хранилище, выделенное предыдущим вызовом оператора по умолчанию new.

РЕДАКТИРОВАТЬ :

Джеймс Канзе здесь говорит, что

Все еще ответственность оператора delete (или delete []) проверять; стандарт не гарантирует, что ему не будет дан нулевой указатель; стандарт требует, чтобы он был неактивным, если ему дан нулевой указатель. Или, что реализация может вызвать это. Согласно последнему проекту, «значение первого аргумента, предоставленного функции освобождения, может быть нулевым значением указателя; если это так, и если функция освобождения предоставлена ​​в стандартной библиотеке, вызов не имеет никакого эффекта». Я не совсем уверен, что подразумевается, что значение этого слова "поставляется в стандартной библиотеке" - буквально, поскольку его функция не предоставляется стандартной библиотекой, предложение, похоже, не применимо , Но почему-то это не имеет смысла.

6 голосов
/ 29 сентября 2010

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

И поэтому, при вызове перегруженного удаления вы должны не проверять NULL.Вы должны полагаться на перегруженное удаление, которое будет реализовано правильно.

3 голосов
/ 29 сентября 2010

из стандартных документов, 18.5.1.1.13 под delete,

Поведение по умолчанию: Если ptr равно нулю, ничего не делает. В противном случае освобождает память, выделенную при предыдущем вызове оператор новый.

Итак, вам не нужно проверять по умолчанию ..

3 голосов
/ 29 сентября 2010

delete (T*)0; действует и ничего не делает, аналогично free(NULL); также действует и ничего не делает. Если вы перегружаете оператор delete, ваша реализация должна иметь ту же семантику. Стандарт говорит о том, как будет работать стандарт delete, но я не думаю, что он говорит о том, как должен вести себя перегруженный delete. Для обеспечения соответствия стандартному / стандартному поведению в качестве входных данных должно быть разрешено (T*)0.

3 голосов
/ 29 сентября 2010

Нет необходимости проверять ноль. оператор delete выполняет проверку на null, поэтому дополнительная проверка не требуется.

2 голосов
/ 29 сентября 2010

Это не необходимо проверить. Если кто-либо перегружает петод, он несет ответственность перед NULL.

2 голосов
/ 29 сентября 2010

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

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

void MyObj::reset()
{
    delete impl_;
    impl_ = 0;    // Needed here - impl_ may be reused / referenced.
}

MyObj::~MyObj()
{
    delete impl_; // No need to assign here as impl_ is going out of scope.
}
1 голос
/ 29 сентября 2010

Я бы сказал, что вопросы содержат неполную информацию. В нашем магазине все еще есть проверка на NULL перед удалением в нашем стандарте кодирования, поскольку у нас все еще есть одна конфигурация компилятора / платформы, которую мы должны поддерживать, которая переходит в неопределенное поведение с оператором defualt delete, если ему передается NULL. Если исходный постер имеет симулированную ситуацию, тогда есть смысл проверить NULL, в противном случае измените стандарт кодирования!

...