将使用goto泄漏variables?
goto
跳过代码而不调用析构函数和事物是否是真的?
例如
void f() { int x = 0; goto lol; } int main() { f(); lol: return 0; }
x
不会泄露?
警告:这个答案只适用于C ++; C中的规则是完全不同的
x
不会泄露?
不,绝对不是。
goto
是一个低级构造,允许您覆盖C ++的内置范围机制,这是一个神话。 (如果有的话,这可能是很容易的)
考虑下面的机制,防止你做标签(包括case
标签)的“坏事”。
1.标签范围
你不能跨越function:
void f() { int x = 0; goto lol; } int main() { f(); lol: return 0; } // error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..]标签的范围是它出现的function。 [..]
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]:
[..]从一个循环中移出一个块,或者通过一个带有自动存储持续时间的初始化variables返回,包括在转移点范围内具有自动存储持续时间的对象的销毁从而不是转移到的点。 [..]
即使未明确初始化, 也不能跳入对象的范围 :
int main() { goto lol; { std::string x; lol: x = ""; } } // error: jump to label 'lol' // error: from here // error: crosses initialization of 'std::string x'
…除了某些types的对象 ,语言可以处理,因为它们不需要“复杂”的构造:
int main() { goto lol; { int x; lol: x = 0; } } // OK
[n3290: 6.7/3]:
可以将其转换为块,但不能绕过具有初始化的声明。 从具有自动存储持续时间的variables不在范围内的点跳转到在范围内的点跳转的程序是格式不正确的,除非variables具有标量types,具有简单的默认构造函数和简单的析构函数的类types,这些types之一的cv限定版本,或者前面types之一的数组,并声明没有初始值设定项。 [..]
3.跳过其他物体的范围
同样,具有自动存储时间的对象在超出范围时不会 “泄漏” :
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)的对象已经在该范围内构build,按照其构造的相反顺序销毁。 [..]
结论
上述机制确保goto
不会让你打破语言。
当然,这并不意味着你应该使用goto
来解决任何问题,但是这确实意味着它不像常见的神话让人们相信那样是“邪恶的”。