是真的,goto
跳过代码位而不调用析构函数和东西?
。
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
x
不会泄漏吗?
警告:此答案仅适用于c++ ;c的规则完全不同。
x
不会泄漏吗?
不,绝对不行
这是一个神话,goto
是一些低级结构,允许您覆盖c++的内置作用域机制。(如果有的话,longjmp
可能容易出现这种情况。)
考虑以下机制,以防止您使用标签(包括case
标签)做"坏事"。
1。h2标签范围
你不能跳过函数:
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
来解决任何给定的问题,但它确实意味着它并不像人们普遍认为的那样"邪恶"。