警告:此答案仅适用于 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’
如果你在对象初始化过程中跳转返回,那么the object's previous "instance" is destroyed:
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’
...除了certain kinds of object,语言可以处理,因为它们不需要“复杂”的构造:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:可以转入区块,但不能转入
一种通过初始化绕过声明的方法。一个程序
从具有自动存储持续时间的变量的点跳转
不在范围内到它在范围内的程度是格式错误的,除非
该变量具有标量类型,具有微不足道的默认值的类类型
构造函数和普通析构函数,其中之一的 cv 限定版本
这些类型,或上述类型之一的数组,并被声明
没有初始化程序。 [..]
3。跳跃遵守其他对象的范围
同样,具有自动存储持续时间的对象are not "leaked" when you goto out of their scope:
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,但它确实意味着它不像常见的神话那样“邪恶”引导人们相信。