Это неопределенное поведение, чтобы удалить пустой указатель void *? - PullRequest
28 голосов
/ 30 мая 2011

Я знаю, что delete использование нулевого указателя является недопустимым:

В любой из альтернатив, если значение операнда удаления является нулевым указателем, операция не имеет никакого эффекта.
(C ++ Standard 5.3.5 [expr.delete] p2)

А также, что удаление указателя void* является неопределенным поведением, поскольку деструктор не может быть вызван, так как нет объектовтипа void:

В первом альтернативном варианте (delete object) значение операнда удаления должно быть указателем на объект, не являющийся массивом, или указателем наподобъект, представляющий базовый класс такого объекта. Если нет, поведение не определено.
(C ++ Standard 5.3.5 [expr.delete] p2)

Теперь,обычно я понимаю, что вещи, перечисленные вначале, имеют приоритет над вещами, которые перечислены позже, но как насчет нулевого указателя void* как следующего?

void* p = 0;
delete p; // UB or well-defined?

Ответы [ 3 ]

12 голосов
/ 30 мая 2011

Интересно, как можно достичь ситуации, когда вы удаляете указатель, только если он нулевой? Но оставаясь в режиме языковой адвокатуры ...

В С ++ 03

5.3.5 / 1

операнд удаления должен иметь тип указателя или тип класса, имеющий одно преобразование в тип указателя.

void * - тип указателя, поэтому нулевой указатель void соответствует статическому требованию.

5.3.5 / 2

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

И это дает желаемое поведение.

5.3.5 / 3

В первом альтернативном варианте (удаление объекта), если статический тип операнда отличается от его динамического типа, статический тип должен быть базовым классом динамического типа операнда, а статический тип должен иметь виртуальный деструктор или поведение не определено.

Это не имеет значения, нулевой указатель не ссылается на объект, для которого проверяется дополнительное ограничение.

В C ++ 0X

5.3.5 / 1

Операнд должен иметь указатель на тип объекта или тип класса, имеющий одну неявную функцию преобразования (12.3.2) в указатель на тип объекта.

void * не является указателем на тип объекта, поэтому должен быть отклонен.

8 голосов
/ 30 мая 2011

§5.3.5 / 3 говорит,

В первом варианте (удалить объект), если статический тип операнд отличается от его динамического тип, статический тип должен быть базовым класс динамического типа операнда и статический тип должен иметь виртуальный деструктор или поведение не определено. Во втором варианте (удалить массив), если динамический тип удаляемый объект отличается от его статический тип, поведение не определен 73

В сноске написано:

73 - Это означает, что объект нельзя удалить с помощью указателя типа void *, поскольку нет объектов типа void.

Так что да, это UB.

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


EDIT:

Есть другая тема, которая также цитирует то же самое и говорит UB:

Безопасно ли удалять пустой указатель?

2 голосов
/ 30 мая 2011

Я считаю, что его неопределенное поведение. new void не разрешено (вам не разрешено создавать объекты типа void), поэтому вызов delete для void* также не имеет смысла. Неважно, если он указывает на NULL или нет. Я бы никогда не использовал такую ​​вещь в моем коде.

...