goto
跳过代码而不调用析构函数和事物是真的吗?
e.g。
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
不会x
被泄露吗?
答案 0 :(得分:206)
警告:此答案仅适用于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’
如果你跨对象初始化跳回,那么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限定版本 声明这些类型或前面类型之一的数组 没有初始化器。 [..]
同样,具有自动存储持续时间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
来解决任何问题,但确实意味着它不像“邪恶”那样共同的神话引导人们相信。