Ответ 1
Goto не может пропустить инициализацию переменных, потому что соответствующие объекты не будут существовать после перехода, так как время жизни объекта с нетривиальной инициализацией начинается при выполнении этой инициализации:
C++ 11 §3.8/1:
[…] Время жизни объекта типа T начинается, когда:
хранение с правильным выравниванием и размером для типа T, и
если объект имеет нетривиальную инициализацию, его инициализация завершена.
C++ 11 §6.7/3:
Можно передавать в блок, но не так, чтобы обойти объявления с инициализацией. Программа, которая переходит от точки, в которой переменная с автоматическим хранением находится вне области действия, до точки, в которой она находится в области видимости, является плохо сформированной, если переменная не имеет скалярного типа, типа класса с тривиальным конструктором по умолчанию и тривиальным деструктором, cv-квалифицированная версия одного из этих типов или массив одного из предыдущих типов и объявляется без инициализатора (8.5).
Поскольку в ошибке упоминается [-fpermissive]
, вы можете включить ее в предупреждение, указав этот флаг компилятора. Это указывает на две вещи. То, что раньше это было разрешено (переменная существовала, но не была инициализирована после перехода), и что разработчики gcc считают, что спецификация запрещает это.
Компилятор только проверяет, должна ли переменная быть инициализирована, а не использовалась ли она, иначе результаты будут довольно противоречивыми. Но если вам больше не нужна переменная, вы можете закончить ее время жизни, сделав "tail-goto" жизнеспособным:
int main() {
int a =0;
goto exit;
{
int *b = NULL;
}
exit:
return 0;
}
совершенно верно.
Напомним, что файл имеет расширение .c
, что предполагает, что это C, а не C++. Если вы компилируете его с помощью gcc
вместо g++
, он должен скомпилироваться, потому что у C нет этого ограничения (у него есть ограничение только для массивов переменной длины, которых вообще нет в C++).