Что "Won't x be leaked"значит? Тип x- это встроенный тип данных. Почему бы тебе не выбрать лучший пример?
Nawaz
2
@Nawaz: Пример и так идеален. Почти каждый раз, когда я говорю с кем-нибудь goto, они думают, что даже автоматические переменные продолжительности хранения каким-то образом «просочились». То, что мы с вами знаем иное, совершенно не относится к делу.
Гонки легкости на орбите,
1
@David: Я согласен с тем, что этот вопрос имеет гораздо больше смысла, когда переменная имеет нетривиальный деструктор ... и я просмотрел ответ Томалака и нашел такой пример. Кроме того, в то время как intне может течь, это может быть утечка . Например: void f(void) { new int(5); }утечка int.
Бен Фойгт,
Почему бы не изменить вопрос на что-то вроде «В приведенном примере будет ли путь выполнения кода передаваться от f () к main () без очистки стека и других функций возврата из функции? Будет ли иметь значение, если деструктор должен быть называется? Это то же самое в C? " Сможет ли это поддержать цель вопроса и избежать возможных неправильных представлений?
Джек В.
Ответы:
210
Предупреждение: Этот ответ относится к C ++ только ; в C.
Не xбудет утечки?
Нет, абсолютно нет.
Это миф, что gotoнекоторая низкоуровневая конструкция позволяет вам переопределить встроенные в C ++ механизмы определения области видимости. (Во всяком случае, это longjmpможет быть подвержено этому.)
Рассмотрим следующий механизм, который не позволит вам делать «плохие вещи» с ярлыками (включая caseярлыки).
1. Объем ярлыка
Вы не можете перепрыгивать через функции:
voidf(){
int x = 0;
goto lol;
}
intmain(){
f();
lol:
return0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:[..] Объем метки - это функция, в которой она появляется. [..]
2. Инициализация объекта
Вы не можете перепрыгнуть через инициализацию объекта:
intmain(){
goto lol;
int x = 0;
lol:
return0;
}
// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘int x’
structT {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
intmain(){
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]:[..] Передача из цикла, из блока или обратно через инициализированную переменную с автоматической продолжительностью хранения включает в себя уничтожение объектов с автоматической продолжительностью хранения, которые находятся в области видимости в точке передачи, но не в точке, переданной в . [..]
Вы не можете перейти в область видимости объекта, даже если он не инициализирован явно:
intmain(){
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’// error: from here// error: crosses initialization of ‘std::string x’
... за исключением определенных типов объектов , которые язык может обрабатывать независимо от того, что они не требуют "сложной" конструкции:
intmain(){
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:Можно передать в блок, но не в обход объявлений с инициализацией. Программа, которая перескакивает из точки, где переменная с автоматической продолжительностью хранения не находится в области видимости, к точке, где она находится в области видимости, плохо сформирована, если только переменная не имеет скалярный тип, тип класса с тривиальным конструктором по умолчанию и тривиальный деструктор, a Версия одного из этих типов с квалификацией cv или массив одного из предыдущих типов объявляется без инициализатора. [..]
[n3290: 6.6/2]:При выходе из области видимости (независимо от ее выполнения) объекты с автоматической продолжительностью хранения (3.7.3), которые были созданы в этой области, уничтожаются в порядке, обратном их построению. [..]
Вывод
Вышеупомянутые механизмы гарантируют, что gotoвы не сломаете язык.
Конечно, это не означает автоматически , что вы «должны» использовать gotoдля любой данной проблемы, но это действительно означает , что это не так «зла» , как общий миф заставляет людей верить.
Вы можете заметить, что C не предотвращает всех этих опасных вещей.
Даниэль,
13
@ Дэниел: Вопрос и ответ очень конкретно касаются C ++, но справедливо. Может быть, у нас есть еще один FAQ, развеивающий миф о том, что C и C ++ - это одно и то же;)
Lightness Races in Orbit
3
@Tomalak: Я не думаю, что мы здесь не согласны. Многие ответы на SO явно где-то задокументированы. Я просто указал на то, что программисту на C может показаться соблазнительным увидеть этот ответ и предположить, что если он работает на C ++, он должен работать аналогично и на C.
Даниэль
2
Вы также можете добавить, что все эти переходы через инициализацию одинаковы для меток case.
PlasmaHH
12
Вау, я только что предположил, что семантика C ++ нарушена для goto, но они на удивление разумны! Отличный ответ.
"Won't x be leaked"
значит? Типx
- это встроенный тип данных. Почему бы тебе не выбрать лучший пример?goto
, они думают, что даже автоматические переменные продолжительности хранения каким-то образом «просочились». То, что мы с вами знаем иное, совершенно не относится к делу.int
не может течь, это может быть утечка . Например:void f(void) { new int(5); }
утечкаint
.Ответы:
Предупреждение: Этот ответ относится к C ++ только ; в C.
Нет, абсолютно нет.
Это миф, что
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
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
Вы не можете перейти в область видимости объекта, даже если он не инициализирован явно:
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
3. Прыжки подчиняются другим объектам.
Кроме того, объекты с автоматической продолжительностью хранения являются не «утечкой» , когда вы
goto
из их сфер :struct T { T() { cout << "*T"; } ~T() { cout << "~T"; } }; int main() { { T t; goto lol; } lol: return 0; } // *T~T
Вывод
Вышеупомянутые механизмы гарантируют, что
goto
вы не сломаете язык.Конечно, это не означает автоматически , что вы «должны» использовать
goto
для любой данной проблемы, но это действительно означает , что это не так «зла» , как общий миф заставляет людей верить.источник