Где в стандарте C ++ сказано: delete может изменить lvalue? - PullRequest
8 голосов
/ 03 августа 2010

Я столкнулся с моим первым компилятором, который изменяет lvalue, переданное на :: delete, но не обнуляет lvalue. То есть верно следующее:

 Foo * p = new Foo();
 Foo * q = p;
 assert(p != 0);
 assert(p == q);
 ::delete p;
 assert(p != q);
 assert(p != 0);

Обратите внимание, что p не равен нулю после операции удаления, и он изменился со своего старого значения. Сотрудник сказал мне, что в его опыте нет ничего необычного, когда он работал с некоторыми компиляторами мэйнфреймов C ++, которые могли бы изменить p на 0xFFFFFFFF, а также с другими компиляторами, которые могли бы изменить p на 0.

Где в стандарте C ++ говорится, что компилятору разрешено делать это?

При поиске в StackOverflow я нашел следующий вопрос: Почему не удаляется установка указателя в NULL? , ответ на который ссылается на ответ Бьярна Страуструпа , который включает в себя утверждение:

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

Я прочитал и перечитал разделы 5.3.5 и 12.5 проекта окончательного комитета стандарта C ++ 0x , но я не вижу "явной" части. Я просто смотрю в неправильные разделы стандарта? Или есть цепочка логики, которая есть в разделах, но я просто не соединяюсь должным образом.

У меня больше нет моей копии Справочного руководства по С ++. Было ли это в ARM, что компилятор мог сделать это?

[Редактировать: Исправление ссылки на разделы с 3.5.3 по 5.3.5. Я также добавляю интересный парадокс в качестве контрапункта к утверждению Хенка о том, что после удаления p не определено.]

Существует интересный парадокс, если p инициализируется нулем.

 Foo * p = 0;
 Foo * q = p;
 assert(p == 0);
 assert(p == q);
 ::delete p;
 assert(p == q);
 assert(p == 0);

В этом случае поведение хорошо документировано. Когда delete получает нулевой указатель, предполагается, что ничего не происходит, поэтому p остается неизменным.

1 Ответ

8 голосов
/ 03 августа 2010

Это может быть не так явно.В 5.3.5 / 7 говорится, что выражение delete будет вызывать функцию deallocator.Затем в 3.7.3.2/4 говорится, что использование освобожденного указателя не определено.Поскольку значение указателя нельзя использовать после освобождения, то не имеет значения, будет ли указатель сохранять значение или значение будет изменено реализацией.

5.3.5 / 7

Выражение удаления вызовет функцию освобождения (3.7.3.2).

3.7.3.2 / 4

Еслиаргумент, данный функции освобождения в стандартной библиотеке, является указателем, который не является нулевым значением указателя (4.10), функция освобождения должна освободить хранилище, на которое ссылается указатель, делая недействительными все указатели, ссылающиеся на любую часть освобожденного хранилища, Эффект от использования недопустимого значения указателя (включая передачу его функции освобождения) не определен .

Ссылки взяты из текущего стандарта.В следующем стандарте 5.3.5 / 7 было изменено:

C ++ 0x FD 5.3.5 / 7

Если значение операнда выражения удаления равноне нулевое значение указателя, выражение удаления вызовет функцию освобождения (3.7.4.2).В противном случае не определено, будет ли вызвана функция освобождения.[Примечание: функция освобождения вызывается независимо от того, генерирует ли деструктор для объекта или некоторого элемента массива исключение.- примечание конца]

...