goto跳过代码而不调用析构函数和事物是真的吗?
例如
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
Run Code Online (Sandbox Code Playgroud)
会不会x泄露?
Lig*_*ica 207
警告:此答案仅适用于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
Run Code Online (Sandbox Code Playgroud)
[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’
Run Code Online (Sandbox Code Playgroud)
如果你跳背跨对象初始化,则该对象的以前的"实例"被破坏:
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
Run Code Online (Sandbox Code Playgroud)
[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’
Run Code Online (Sandbox Code Playgroud)
...除了某些类型的对象,语言可以处理,因为它们不需要"复杂"构造:
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
Run Code Online (Sandbox Code Playgroud)
[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
Run Code Online (Sandbox Code Playgroud)
[n3290: 6.6/2]:在从范围退出(但是已完成)时,在该范围内构造的具有自动存储持续时间(3.7.3)的对象将按其构造的相反顺序销毁.[..]
上述机制确保goto不会让您破坏语言.
当然,这并不意味着你"应该" goto用于任何给定的问题,但它确实意味着它不像普通神话引导人们相信的那样"邪恶".