警告:此答案仅与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
任何给定的问题,但这确实意味着它不像普通神话所引起的人们那样相信“邪恶”。