Подтвердить что ты не робот

Готово до определения переменной - что происходит с его значением?

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

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 в соответствии со стандартом С++? Или компилятор может занять регистр, в котором a хранится в goto до места до a?

4b9b3361

Ответ 1

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


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

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

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

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

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

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

Изменить # 2: Прочитав ваш комментарий о возможном уничтожении int a из-за перехода назад, я нашел это (высказывания 6.6 Jump, выделив мой):

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

Один, int a не инициализирован, и это не объект, если я правильно понимаю стандартную терминологию.

Ответ 2

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

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

Итак, это должно быть хорошо.

Тогда в 6.6/2:

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

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

См. 6.7/2:

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

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

Ответ 3

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

Ответ 4

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

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

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