“Чтение” результата преинкремента POD не приводит к неопределенному поведению. Почему точно?

Это - глупый вопрос.:)

[РЕДАКТИРОВАНИЕ: глупый или нет, это оказалось вопросом об особенности C++, см. UPDATE_2]

Предположим, что мы имеем:

int a = 0; // line 1
int b = ++a; // line 2

То, что происходит в строке 2, (примечание, числа являются просто маркерами и не указывают точный порядок):

                      = [1: write result of (3) to result of (2)]
                     /\
[2: take "b" l-value] [3: convert result of (4) to an r-value ]
                      |
                      [4: take "a" l-value, "increment" and return it]

"Запись" в (4) "заказана" перед "чтением" в (3), и так как нет никаких точек последовательности между, побочного эффекта, как гарантируют, не произойдет прежде (3) (существует также "чтение" в (4) само, но заказанный перед "записью", так, чтобы не приводил к UB).

Так, где ошибка в вышеупомянутом?

[ОБНОВЛЕНИЕ, к которому стремятся не закаленные адвокаты точки последовательности :)]

Другими словами, проблема:

  1. Кажется, существует "конкуренция", происходит ли l-value-to-r-value преобразование ("чтение") или инкремент ("запись") побочный эффект сначала.

  2. В C, который дал бы UB, по данным JTC1/SC22/WG14 N926 "Анализ Точки Последовательности" * (см., например, ПРИМЕР 5: int x,y; (x=y) + x; // UB).

  3. Обратите внимание, что это не было бы случаем, должен, постинкремент использоваться с тех пор (3) и (4) составит сингл [(3): возьмите "a" l-значение, преобразуйте его в r-значение и возврат что r-значение] с побочным эффектом "записи", отложенным до где-нибудь перед следующей точкой последовательности

_

(*) Это похоже на самое чистое систематическое объяснение для темы, данной членами комитета Стандартов C99.

[UPDATE_2]

  1. Урок извлечен: никогда не судите C++ по правилам C :)). Я сделал точно, что, задаваясь вопросом, почему N926 (который чисто описывает способ C99 вещей) был "не достаточно ясен" по теме преинкрементов, приводящих к l-значениям.

  2. Вопрос возникает, как можно было бы создать подобное объяснение для C++, поскольку нет один, так как даже в случае C, просто интерпретирующем стандарт, довольно твердо, и стандарт языка C++ намного более сложен и неясен.

[UPDATE_3]

Существует обсуждение, имеющее дело с некоторыми соответствующими темами (по крайней мере, в ~newer половине) в "Неопределенности общего выражения". плюс вопрос обсужден людьми комитета здесь (см. "222. Точки последовательности и lvalue-возврат операторов").

7
задан mlvljr 13 August 2011 в 07:40
поделиться

2 ответа

Думаю, решение может быть в формулировке «++ i». Он говорит: «Значение - это новое значение операнда; это lvalue.». И поведение не определено в 5/4 как «Кроме того, к предыдущему значению нужно обращаться только для определения значения, которое будет сохранено».

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

На самом деле «предыдущее значение» звучит для меня как «значение, которое объект имел в предыдущей точке последовательности». И если так интерпретировать, то эта конструкция выглядит неопределенной. Но если мы напрямую сравним формулировку «++ i» в 5.3 / 2 с 5/4, мы столкнемся с «новым значением» и «предыдущим значением», и все будет «склонно» к определенному поведению («++ i "будет смотреть на значение" i "в следующей точке последовательности и выдавать это значение как содержимое результирующего lvalue" ++ i ").

2
ответ дан 7 December 2019 в 16:41
поделиться

Основное предложение в C++ 5/4 следующее

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

(А предложение, процитированное Йоханнесом, является следующим, подчиненным.)

Какой скалярный объект, как вы подозреваете, здесь изменяет свое хранимое значение более одного раза? a и b модифицируются по одному разу в строке 2, так что проблемы нет.

(Похожий язык есть в 6.5/2 в стандарте C. )


EDIT:

Запись в (4) "упорядочена" перед чтением в (3), и поскольку между ними нет точек последовательности, побочный эффект не гарантирован, что он произойдет до (3)

Перечитав ваш вопрос, я думаю, что путаница происходит из-за неправильного представления о ++a: выражение на самом деле не заглядывает в будущее значение a. Скорее, можно думать о ++a как о "возврате a+1 и как побочном эффекте инкременте a, в свое удовольствие (до следующей точки последовательности)".

Так какая разница, произойдет ли этот побочный эффект до или после (3)? Значение выражения, которое и подается в (3), уже определено.

1
ответ дан 7 December 2019 в 16:41
поделиться