Перейти к определению переменной - что происходит с ее значением? - PullRequest
17 голосов
/ 22 июля 2011

Вот несколько вопросов, которые меня интересуют. Учитывая следующий код, можем ли мы быть уверены в его выводе?

void f() {
  int i = 0; 
  z: if(i == 1) goto x; else goto u; 
  int a; 
  x: if(a == 10) goto y; 
  u: a = 10; i = 1; goto z; 
  y: std::cout << "finished: " << a; 
}

Гарантируется ли вывод finished: 10 в соответствии со стандартом C ++? Или же компилятор может занимать регистр, в котором хранится a, когда goto до места, предшествующего a?

Ответы [ 4 ]

6 голосов
/ 22 июля 2011

Примечание: Сначала прочитайте комментарии к этому. Йоханнес более или менее сбил весь мой аргумент одной удачной стандартной цитатой. ; -)


У меня нет стандарта C ++, поэтому мне нужно экстраполировать его из стандарта C.

Довольно удивительно (для меня) глава 6.2.1 Области применения идентификаторов ничего не говорит о сфере действия идентификатора, начиная с момента его объявления (как я бы догадался). int a, в вашем примере, имеет область видимости блока, которая «заканчивается в конце соответствующего блока», и это все, что сказано об этом. глава 6.8.6.1 Оператор goto говорит, что "оператор goto не должен переходить из области видимости идентификатора, имеющего переменно измененный тип, в область видимости этого идентификатора" - но поскольку ваши goto s перепрыгнуть только в пределах блока (и, таким образом, область действия int a, что кажется приемлемым для ISO / IEC 9899: 1999.

Я довольно удивлен этим ...

Редактировать # 1: Быстрый Google, позже я получил окончательный вариант C ++ 0x. Соответствующее заявление, я думаю, таково здесь (6,7 Заявление декларации , выделив мое):

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

Я думаю, что ваш код в порядке по стандартам стандарта. Но неприятно, заметьте. ; -)

Редактировать # 2: Читая ваш комментарий о возможном уничтожении int a из-за прыжка назад, я обнаружил это (6,6 операторов Jump , выделив мой):

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

Во-первых, int a не "инициализирован" и не является объектом, если я правильно понимаю стандартную терминологию.

5 голосов
/ 22 июля 2011

6.7 / 3 говорит, что

Программа, которая переходит из точки, в которой локальная переменная с автоматическим хранением находится вне области действия, в точку, где она находится в области действия, плохо информирована, если переменная не имеетТип POD (3.9) и объявлен без инициализатора (8.5).

Так что все должно быть в порядке.

Тогда в 6.6 / 2:

При выходе из области (хотя и выполненной) деструкторы (12.4) вызываются для всех построенных объектов с автоматической продолжительностью хранения (3.7.2) (именованные объекты или временные объекты), которые объявлены в этой области, в обратном порядке их объявления..

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

См. 6.7 / 2:

Переменные с автоматическим хранением (3.7.2) инициализируются каждый раз, когда выполняется их декларация.Переменные с автоматическим хранением, объявленные в блоке, уничтожаются при выходе из блока (6.6).

Так что мне кажется, что нет гарантии, что вы получите 10, хотя кажетсяТрудно представить компилятор, в котором этого не было бы.

0 голосов
/ 22 июля 2011

Гарантируется ли вывод finished: 10 в соответствии со стандартом C ++?

Я думаю, да, это должно!

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

0 голосов
/ 22 июля 2011

Запрещено отказываться от определения переменной.Это должна быть ошибка.

...