Требует ли стандарт преобразования lvalue в rvalue переменной-указателя при применении косвенности?

StackOverflow https://stackoverflow.com//questions/21053273

Вопрос

ТЛ;ДР

Учитывая следующий код:

int* ptr;
*ptr = 0;

делает *ptr требуют преобразование lvalue в rvalue преобразование ptr перед применением косвенности?

Стандарт охватывает тему преобразование lvalue в rvalue во многих местах, но, похоже, не содержит достаточной информации, чтобы определить, является ли * оператор требуют такого преобразования.

Подробности

А преобразование lvalue в rvalue преобразование рассматривается в N3485 в разделе 4.1 Преобразование Lvalue в Rvalue параграф 1 и говорит(акцент мой, иду вперед):

GLVALUE (3.10) нефункционального типа T может быть преобразована в PRVALUE.53 Если T является неполным типом, программа, которая требует этого преобразования, плохо сформирована.Если объект, к которому относится GLVALUE, не является объектом типа T и не является объектом типа, полученного из T, Или, если объект ненициализирован, программа, которая требует этого преобразования, имеет неопределенное поведение.[...]

Как и *ptr = 0; требуют этого преобразования?

Если мы зайдём в раздел 4 параграф 1 там написано:

[...] К выражению будет применена стандартная последовательность преобразования если необходимо чтобы преобразовать его в требуемый тип назначения.

Так когда же это необходимый?Если мы посмотрим на раздел 5 Выражения тот преобразование lvalue в rvalue преобразование упомянуто в пункте 9 который говорит:

Всякий раз, когда выражение GLVALUE появляется как операнд оператора, который ожидает PRVALUE для этого операнда, стандартные преобразования (4.3) (4.1), массив к указателю (4.2) или функционирование (4.3) применяется для преобразования выражения в PrValue.[...]

и абзац 11 который говорит:

В некоторых контекстах выражение появляется только из-за его побочных эффектов.Такое выражение называется выброшенным выражением стоимости. ...

ни один из абзацев, по-видимому, не применим к этому примеру кода и 5.3.1 Унарные операторы параграф 1 там написано:

Унарный оператор * выполняет косвенное обращение:Выражение, к которому оно применяется, должно быть указателем на тип объекта или указатель на тип функции, а результат - это LVALUE, ссылаясь на объект или функцию, на которую указывает выражение.Если тип выражения является «указателем на T», тип результата - «T.» [ Примечание:Крайение через указатель на неполный тип (кроме CV void) является действительным.Полученный таким образом, полученная таким образом может использоваться ограниченными способами (например, для инициализации ссылки);Этот LVALUE не должен быть преобразован в PRValue, см. 4.1.—конечная заметка]

кажется, это не требует ценить указателя, и я не вижу никаких требований для преобразования указателя, я что-то упускаю?

Почему нас это волнует?

Я видел ответ и комментарии в других вопросах, в которых утверждается, что использование неинициализированного указателя является неопределенным поведением из-за необходимости преобразование lvalue в rvalue преобразование ptr прежде чем применять косвенность.Например: Где именно стандарт C++ говорит, что разыменование неинициализированного указателя является неопределенным поведением? выдвигает этот аргумент, и я не могу согласовать этот аргумент с тем, что изложено ни в одной из последних черновых версий стандарта.Поскольку я видел это несколько раз, я хотел получить разъяснения.

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

Это было полезно?

Решение 2

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

дип указал мне на две соответствующие темы, которые охватывают очень схожие темы:

Похоже, что консенсус заключается в том, что стандарт неопределенный и поэтому не могу дать ответ, который ищу, Джозеф Мэнсфилд опубликовал отчет о дефекте по поводу отсутствия спецификации, и похоже, что это все еще открыть и неясно, когда это может быть разъяснено.

Можно привести несколько аргументов здравого смысла относительно намерение стандарта.Можно спорить Логически операнд является ценным значением, если операция требует использования значения этого операнда..Другой аргумент заключается в том, что если мы оглянемся назад на Проект стандарта C99 говорит преобразование lvalue в rvalue выполняется по умолчанию и исключения отмечены.Соответствующий раздел проекта стандарта C99: 6.3.2.1 L-значения, массивы и обозначения функций параграф 2 который говорит:

За исключением случаев, когда это операнд оператора sizeof, унарного оператора &, оператора ++, оператора -- или левого операнда оператора .Оператор или оператор назначения, LVALUE, который не имеет типа массива, преобразуется в значение, хранящееся в назначенном объекте (и больше не является LVALUE).[…]

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

Когда я пытался прояснить, доказательство неопределенного поведения было менее важным, чем выяснение того, является ли обязательным преобразование lvalue в rvalue.Если мы хотим доказать неопределенное поведение, у нас есть альтернативные подходы.Подход Джерри основан на здравом смысле, и в этом косвенность требует, чтобы выражение было указателем на объект или функцию, а неопределенное значение только случайно указывало на действительный объект. В целом, проект стандарта C++ не дает явного заявления о том, что использование неопределенного значения не определено, в отличие от проекта стандарта C99. В C++11 и более поздних версиях стандарт не дает явного заявления о том, что использование неопределенного значения не определено.Исключением являются итераторы и указатели расширений, у нас есть концепция единственное значение и нам рассказывают в разделе 24.2.1 что:

[…][ Пример:После объявления неинициализированного указателя x (как и в случае с int* x;), всегда следует предполагать, что x имеет единственное значение указателя.—end example ] […] Значения, допускающие разыменование, всегда несингулярны.

и:

Недопустимый итератор — это итератор, который может быть единственным.268

и сноска 268 гласит:

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

В С++1y язык меняется, и у нас есть явный оператор, в котором используется промежуточное значение, неопределенное, за некоторыми узкими исключениями..

Другие советы

Я думаю, вы подходите к этому с довольно косой точки зрения, так сказать.Согласно §5.3.1/1:

Унарный * оператор выполняет косвенность:Выражение, к которому оно применяется, должно быть указателем на тип объекта или указатель на тип функции, а результат - это LVALUE, ссылаясь на объект или функцию, на которую указывает выражение.Если тип выражения — «указатель на T», тип результата — «T».

Хотя здесь не говорится о преобразовании lvalue в rvalue, требуется, чтобы выражение было указателем на объект или функцию.Неинициализированный указатель не будет (за исключением, возможно, случайного) ничего подобного, поэтому попытка разыменования приводит к неопределенному поведению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top