Что касается "first" - y
должен быть доступен при инициализации z
, но я не думаю, что результат этого доступа должен использоваться для вычисления z
, , если реализация почему-то знает, что она должна быть 2. Для этой программы (я думаю) есть только 2 способа, которыми она может иметь любое другое значение:
- это модифицируется отладчиком или другим вмешательством в программу.
- загрузчик помещает изменчивые глобальные переменные в некоторую область памяти, которая не работает как обычная память на вашем оборудовании. (в этом случае это было бы очень странное поведение, определяемое реализацией, до такой степени, что я не думаю, что это законно для написанного кода, но важно, если программа или какая-то часть процесса сборки вне программы может каким-то образом контролировать, где заканчивается объект).
Обе эти вещи могут быть исключены реализацией - во втором случае, зная, как ведет себя загрузчик, во-первых, устанавливая ограничения на то, что вы можете надеяться достичь с помощью отладчика («запись изменяемых переменных приводит к удивительное поведение "). Разочаровывает пользователя отладчика, но стандарт не ограничивает работу отладчиков или то, что «фактически» содержится в памяти, он просто ограничивает то, что делают допустимые реализации и программы C ++ и что «видит» C ++.
На практике вы могли бы подумать, что компилятор не потрудится рассматривать изменчивый объект как подлежащий оптимизации. Это неконстантный объект, и вы должны подозревать, что единственная причина для определения неконстантного изменчивого объекта заключается в том, что он будет меняться так, как компилятор не ожидает [*]. Вы бы надеялись, что он просто прочитает y
и выполнит деление, но я считаю, что дело может быть сделано для оптимизации законным.
Что касается «второго» - в случае вашей программы компилятор может инициализировать d
с предварительно вычисленным значением по правилу «как если», при условии, что он знает, что производит деление значения. По этому вопросу в вашей программе он может удалить d
полностью.
«При условии, что он знает, что производит деление значений», зависит от реализации - если он поддерживает изменения режимов округления IEEE или эквивалентных, и если он не знает, какой режим должен быть в силе, то в общем случае он не знает заранее результат даже простой арифметики.
Правило "как будто" покрывает, скажем, 85% оптимизаций компилятора. Это описано в разделе 1.9 стандарта, который стоит посмотреть. Я согласен, что документ в целом довольно пугающий, и язык, который он использует, иногда непроницаем, но вам нужно с чего-то начинать, поэтому начните с того, что вам сейчас интересно; -)
[*] В частности, и это никак не рассматривается в стандарте C ++ 03, некоторые компиляторы (Microsoft) используют volatile
в своем определении семантики потоков.