NULL перед удалением объекта с перегруженным удалением
Это стало одним из комментариев к обзору кода.
Хорошо ли проверять NULL перед вызовом delete для любого объекта?
Я понимаю, что оператор delete проверяет для NULL внутренне и является избыточным, но аргумент, который был указан, был удалён, поскольку оператор может быть перегружен, и если перегруженная версия не проверяет NULL, она может быть повреждена. Так безопасно и разумно предположить, что если и когда удаление будет перегружено, он будет проверять NULL или нет?
В моем понимании разумно предположить, что первый случай, когда перегруженный delete должен позаботиться о проверке NULL, и точка обзора не устраивает. Как вы думаете?
Ответы
Ответ 1
Нет, не проверяйте значение null. В стандарте указано, что delete (T*)0;
действителен. Это просто усложнит ваш код без каких-либо преимуществ. Если operator delete
перегружено, лучше проверить значение null в реализации оператора. Просто сохраняет строки кода и ошибки.
EDIT:. Этот ответ был принят и одобрен, но, на мой взгляд, он не был очень информативным. Здесь есть один недостающий кусок, и, ради совести, позвольте мне добавить этот последний фрагмент здесь.
Стандарт фактически говорит в [basic.stc.dynamic], по крайней мере, с С++ 03:
Любые функции распределения и/или освобождения, определенные в программе на С++, включая версии по умолчанию в библиотеке, должны соответствовать семантике, указанной в пунктах 3.7.4.1 и 3.7.4.2.
В тех случаях, когда ссылочные разделы, а также некоторые другие места в стандарте, перечисленные в других ответах, говорят, что семантика передачи нулевого указателя является no-op.
Ответ 2
Я бы сказал, что это еще одна причина для того, чтобы, если вы перегрузили operator delete
, тогда вы всегда должны проверить его на NULL
, иначе вы нарушаете семантику.
Ответ 3
Хорошо ли проверить NULL перед вызовом delete для любого объекта?
Нет!
int *p = NULL;
delete p ; //no effect
В стандарте говорится [Раздел 5.3.5/2]
Если операнд имеет тип класса, операнд преобразуется в тип указателя, вызывая вышеупомянутую функцию преобразования, а преобразованный операнд используется вместо исходного операнда для остальной части этого раздела. В любой альтернативе , если значение операнда delete является нулевым указателем, операция не имеет эффекта.
Кроме того, в разделе 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 восстанавливает хранилище, выделенное более ранним вызовом для нового оператора по умолчанию.
ИЗМЕНИТЬ:
Джеймс Канзе здесь говорит, что
По-прежнему сохраняется вероятность удаления оператора (или удаления []) для проверки; стандарт не гарантирует, что ему не будет присвоен нулевой указатель; стандарт требует, чтобы он был не-op, если был задан нулевой указатель. Или, что реализация разрешена для вызова. Согласно последнему проекту: "Значение первого аргумента, переданного функции дезадаптации, может быть значением нулевого указателя, и если функция освобождения включена в стандартную библиотеку, вызов не имеет никакого эффекта". Я не совсем уверен, что последствия того, что "есть тот, который поставляется в стандартной библиотеке", должны быть приняты буквально, поскольку его функция не входит в стандартную библиотеку, предложение, похоже, не будет применяться, Но почему-то это не имеет смысла.
Ответ 4
Я бы сказал, что ответственность за перегрузку delete
лежит в том, как вы ожидаете, что delete
будет вести себя. То есть, он должен обрабатывать указатели NULL как нет-op.
Итак, при вызове перегруженного удаления вы не должны проверять значение NULL. Вы должны полагаться на перегруженное удаление, которое должно быть правильно реализовано.
Ответ 5
Нет необходимости проверять значение null. оператор delete делает chck для null, поэтому дополнительная проверка не требуется.
Ответ 6
delete (T*)0;
действителен и ничего не делает, аналогично free(NULL);
также действителен и ничего не делает. Если вы перегрузите оператор delete
, ваша реализация должна нести ту же семантику. В стандарте указано, как будет работать стандартный delete
, но я не думаю, что он говорит о том, как должен себя вести перегруженный delete
. Для согласованности со стандартным/стандартным поведением он должен позволить (T*)0
в качестве ввода.
Ответ 7
Из стандартных документов, 18.5.1.1.13 в разделе delete
,
Поведение по умолчанию: Если значение ptr равно null, ничего не делает. В противном случае восстанавливает хранилище, выделенное предыдущим вызовом оператора new.
Итак, вам не нужно проверять по умолчанию.
Ответ 8
Не нужно проверять 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.
}
Ответ 9
Требуется ли не проверить. Если кто-то перегружает этот пост, то это его ответственность за то, что с NULL.
Ответ 10
Я бы сказал, что вопросы содержат неполную информацию. Мой магазин все еще имеет чек на NULL, прежде чем удалить в нашем стандарте кодирования, так как у нас еще один компилятор конфигурация/платформы, что мы должны поддерживать, что переходит в поведение undefined с DEFUALT удалить оператор, если он передается NULL. Если исходный плакат имеет симуляционную ситуацию, тогда есть точка для проверки для NULL, иначе измените стандарт кодирования!
Ответ 11
Немного педантичности С++:
NULL не является встроенной концепцией. Да, мы все знаем, что это значит, но в С++ до С++ 0X понятие null-указателя - это просто значение 0. NULL обычно представляет собой специфичный для платформы макрос, который расширяется до 0.
С С++ 0X мы получаем nullptr, который является более четким, чем простой ноль, и не конвертируется ни в один целочисленный тип, кроме bool, и является более понятной концепцией, чем NULL (или, возможно, лучшей реализацией концепции за NULL).