Верно ли, что goto
перескакивает по фрагментам кода без вызова деструкторов и прочего?
e.g.
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Не будет x
утечка?
Верно ли, что goto
перескакивает по фрагментам кода без вызова деструкторов и прочего?
e.g.
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Не будет x
утечка?
Предупреждение: этот ответ относится только к C ++ только; в C. правила совсем другие.
Не будет
x
утечка?
Нет, конечно.
Это миф, что goto
- это некоторая низкоуровневая конструкция, которая позволяет вам переопределять встроенные в C ++ механизмы определения области видимости. (Во всяком случае, это longjmp
, которое может быть подвержено этому.)
Подумайте о следующем механизме, который не позволяет вам делать «плохие вещи» с ярлыками (включая case
ярлыка).
Вы не можете перепрыгивать через функции:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] Объем метки - это функция, в которой она появляется. [..]
Вы не можете перепрыгнуть через инициализацию объекта:
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]:
Можно передать в блок, но не в обход объявлений с инициализацией. Программа, которая перескакивает из точки, где переменная с автоматической продолжительностью хранения не находится в области видимости, к точке, где она находится в области видимости, плохо сформирована, если только переменная не имеет скалярный тип, тип класса с тривиальным конструктором по умолчанию и тривиальный деструктор, a cv-квалифицированная версия одного из этих типов или массив одного из предыдущих типов и объявляется без инициализатора. [..]
Точно так же объекты с автоматической продолжительностью хранения не "утечки", когда вы goto
выходите из их области видимости a >:
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
для решения той или иной проблемы, но это действительно означает, что это не так уж плохо, как заставляет людей верить распространенный миф.
[n3290: 18.10/4]:
. Сигнатура функции longjmp(jmp_buf jbuf, int val)
имеет более ограниченное поведение в этом международном стандарте. Пара вызовов _3 _ / _ 4_ имеет неопределенное поведение, если замена setjmp
и longjmp
на catch и throw вызовет любые нетривиальные деструкторы для любых автоматических объектов. сломать это?
- person Lightness Races in Orbit; 07.09.2011
goto lol; int x = 5; lol: printf("%d", x);
дает warning: ‘x’ is used uninitialized in this function
- person Daniel; 07.09.2011
goto
, существовавшее в C до появления C ++, на самом деле не работает точно так же в C ++.
- person Daniel; 07.09.2011
[n3290: C.1.5]
.
- person Lightness Races in Orbit; 07.09.2011
"Won't x be leaked"
? Типx
- это встроенный тип данных. Почему бы тебе не выбрать лучший пример? - person Nawaz   schedule 07.09.2011goto
, они думают, что даже автоматические переменные продолжительности хранения каким-то образом просочились. То, что мы с вами знаем иное, совершенно не имеет значения. - person Lightness Races in Orbit   schedule 07.09.2011int
не может протекать, он может протекать. Например:void f(void) { new int(5); }
утекаетint
. - person Ben Voigt   schedule 07.09.2011