Ответ 1
Введение:. Первая проблема заключается в том, законно ли использовать значение p
вообще.
После того, как a
был уничтожен, p
получает то, что известно как недопустимое значение указателя. Цитата из N4430 (для обсуждения статуса N4430 см. "Примечание" ниже):
Когда достигнут конец продолжительности области хранения, значения всех указателей, представляющих адрес любой части освобожденного хранилища, становятся недопустимыми значениями указателя.
Поведение, когда используется недопустимое значение указателя, также рассматривается в том же разделе N4430 (и почти идентичный текст появляется в С++ 14 [basic.stc.dynamic.deallocation]/4):
Отказ от недопустимого значения указателя и передача недопустимого значения указателя функции деаллокации имеют поведение undefined. Любое другое использование недопустимого значения указателя имеет поведение, определенное реализацией.
[Сноска: некоторые реализации могут определять, что копирование недопустимого значения указателя вызывает системную ошибку выполнения. - конец сноски]
Поэтому вам нужно будет проконсультироваться с вашей документацией по внедрению, чтобы узнать, что должно произойти здесь (начиная с С++ 14).
Термин, используемый в приведенных выше цитатах означает, требующий преобразования lvalue-to-rvalue, как в С++ 14 [conv.lval/2]:
Когда преобразование lvalue-rvalue применяется к выражению e, а [...] объект, к которому относится ссылка glvalue, содержит недопустимое значение указателя, поведение определяется реализацией.
История:. В С++ 11 этот undefined, а не определенный реализацией; он был изменен на DR1438. См. Историю изменений этого сообщения для полных кавычек.
Приложение к p == q
: Предположим, что мы приняли в С++ 14 + N4430, что результат оценки p
и q
определяется реализацией и что реализация не определить, что происходит аппаратная ловушка; [expr.eq]/2 говорит:
Два указателя сравнивают одинаковые, если оба они равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2), в противном случае они сравниваются неравномерно.
Так как он определяет реализацию, какие значения получаются при оценке p
и q
, мы не можем точно сказать, что произойдет здесь. Но он должен быть либо определенным, либо неопределенным.
g++ проявляет неуказанное поведение в этом случае; в зависимости от коммутатора -O
я мог сказать, что он либо 1
, либо 0
, соответствующий тому, был ли повторно сохранен тот же адрес памяти для b
после a
.
Примечание о N4430: Это предлагаемое разрешение дефекта для С++ 14, которое еще не принято. Он очищает много формулировок, связанных с временем жизни объекта, недействительными указателями, подобъектами, объединениями и доступом к границам массива.
В тексте С++ 14 в разделе [basic.stc.dynamic.deallocation]/4 и последующих абзацах определено недопустимое значение указателя, когда используется delete
. Однако четко не указано, применяется ли тот же принцип к статическому или автоматическому хранению.
В [basic.compound]/3 есть определение "действительный указатель", но оно слишком смутно для разумного использования. [basic.life]/5 (сноска) относится к одному и тому же тексту для определения поведения указателей к объектам статической продолжительности хранения, что предполагает, что он предназначен для применения ко всем типам хранилищ.
В N4430 текст перемещается из этого раздела на один уровень, так что он явно применяется ко всем длинам хранения. Прилагается примечание:
Примечание: это должно относиться ко всем длинам хранения, которые могут закончиться, а не только к динамической длительности хранения. В реализации, поддерживающей потоки или сегментированные стеки, поток и автоматическое хранилище могут вести себя так же, как это делает динамическое хранилище.
Мое мнение: я не вижу последовательного способа интерпретации стандарта (pre-N4430), кроме как сказать, что p
получает недопустимое значение указателя. Поведение, похоже, не охватывает какой-либо другой раздел, кроме того, что мы уже рассмотрели. Поэтому я с удовольствием отношусь к формулировке N4430 как представляющей намерение стандарта в этом случае.