вторник, 8 декабря 2009 г.

Delayed writes

Наверное, уже многие знают, что результат выражения i++ + ++i является неопределенным. Тут вроде все ясно: в operator+ передаются два аргумента и порядок вычисления аргументов может быть любым, что и дает неопределенность. Однако, в стандарте есть гораздо более интересные примеры. Утверждается (С++'03 5/4), что:
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9

i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
Рассмотрим предпоследнее выражение. Допустим, изначально i=0. Интересно, что интуитивно выражение i = ++i + 1 абсолютно определено и непонятно как создатели компилятора могут выдать что-то кроме 2. Однако, стандарт позволяет в реализации делать отложенную запись вычислений. Т. е. в этом последнем примере может быть такая реализация:
  1. Посчитали значение ++i и запомнили в регистре (в переменную i результат запишем позднее).
  2. Считаем результат ++i + 1, взяв результат п. 1.
  3. Записываем в i значение, которое посчитали в п. 2.
  4. О, чуть не забыли. Записываем результат п. 1 в переменную i.
Итого, получили в i значение 1. Такое поведение допускается стандартом в пункте 5 абзац 4:
Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.
В отладочном режиме такого, скорее всего не будет, но при оптимизации очень может быть. Для разработчиков это означает, что, если в выражении переменная меняется более одного раза, то это скорее всего приведет к нежелательным последствиям и трудноуловимым багам.

Ссылки по теме:
Why is `i = ++i + 1` unspecified behavior?
Точки следования (sequence points)

Комментировать в ВКонтакте