Чи правда, що goto
стрибає по бітах коду, не викликаючи деструкторів та інше?
напр
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Чи не x
просочиться?
Чи правда, що goto
стрибає по бітах коду, не викликаючи деструкторів та інше?
напр
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Чи не x
просочиться?
"Won't x be leaked"
означає? Тип x
- це вбудований тип даних. Чому б вам не вибрати кращий приклад?
goto
, вони думають, що навіть автоматичні змінні тривалості зберігання якимось чином "просочуються". Те, що ми з вами знаємо інакше, абсолютно не має значення.
int
не може текти, це може бути витік . Наприклад: void f(void) { new int(5); }
витікає int
.
Відповіді:
Попередження: Ця відповідь відноситься до 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]:
Можна перенести в блок, але не таким чином, щоб обійти оголошення з ініціалізацією. Програма, яка переходить від точки, де змінна з автоматичною тривалістю зберігання не знаходиться в області дії, до точки, де вона знаходиться в області дії, неправильно сформована, якщо змінна не має скалярного типу, типу класу з тривіальним конструктором за замовчуванням і тривіальним деструктором, cv-кваліфікована версія одного з цих типів або масив одного з попередніх типів і оголошується без ініціалізатора. [..]
Крім того, об'єкти з автоматичною тривалістю зберігання є НЕ «витоком» , коли ви 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
для будь-якої даної проблеми, але це дійсно означає , що це не так «зла» , як загальний міф змушує людей вірити.