Предупреждение: Этот ответ относится только к C ++ ;правила совершенно разные в C.
Не будет ли x
утечка?
Нет, абсолютно нет.
Миф о том, что goto
- это некая низкоуровневая конструкция, которая позволяет вам переопределить встроенные в C ++ механизмы определения области действия.(Во всяком случае, это longjmp
, что может быть склонным к этому.)
Рассмотрим следующую механику, которая не позволяет вам делать «плохие вещи» с метками (включая case
метки).
1.Область действия надписи
Нельзя переключаться между функциями:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] Область действия надписи - это функция, в которой она появляется.[..]
2.Инициализация объекта
Вы не можете перейти через инициализацию объекта:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Если вы прыгаете назад через инициализацию объекта, тогда предыдущий "экземпляр" объектауничтожено :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[..] Передача из цикла, из блока или обратно после инициализированной переменной с автоматическим продолжением хранения включает в себя уничтожениеобъекты с автоматической продолжительностью хранения, которые находятся в области действия в точке, из которой они были перенесены, но не в точке, в которую они были перенесены[..]
Вы не можете перейти в область видимости объекта, даже если он явно не инициализирован:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... за исключением навернякавиды объектов , которые язык может обрабатывать независимо от того, что они не требуют "сложной" конструкции:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
Можно передавать в блок, но не вспособ обойти объявления с инициализацией.Программа, которая переходит из точки, в которой переменная с автоматическим хранением находится вне области действия, в точку, в которой она находится в области видимости, является неправильной, если переменная не имеет скалярного типа, типа класса с тривиальным конструктором по умолчанию и тривиальным деструктором,cv-квалифицированная версия одного из этих типов или массив одного из предыдущих типов и объявляется без инициализатора.[..]
3.Прыжки подчиняются области действия других объектов
Аналогично, объекты с автоматической продолжительностью хранения не"просочились", когда вы goto
вышли из их области :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
При выходе из области (хотя и выполненной) объекты с автоматической продолжительностью хранения (3.7.3), созданные в этой области, уничтожаются в порядке, обратном их построению.[..]
Заключение
Приведенные выше механизмы гарантируют, что goto
не позволит вам нарушить язык.
Конечно, этоне означает автоматически, что вы «должны» использовать goto
для решения любой конкретной проблемы, но означает , что это вовсе не так «зло», как обычный миф, заставляющий людей верить.