会使用goto泄漏变量吗? [英] Will using goto leak variables?

查看:121
本文介绍了会使用goto泄漏变量吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

goto 是否真的跳过了大量的代码而不调用析构函数和事情?



p>

  void f(){
int x = 0;
goto lol;
}

int main(){
f();
lol:
return 0;
}

不会 x 警告:此回答仅适用于C ++

;规则在C中是完全不同的。







不会 x 被泄露?




这是一个神话, goto 是一些低级结构,允许你覆盖C ++的内置范围机制。 (如果有的话, longjmp 可能容易出现这种情况。)



用标签(其中包括 case 标签)做坏事。






1。标签范围



您不能跨功能跳转:

  F(){$​​ b $ b int x = 0; 
goto lol;
}

int main(){
f();
lol:
return 0;
}

//错误:使用但未定义的标签'lol'


$ b b


[n3290:6.1 / 1]: [..]标签的作用域是
它出现。 [..]







2。对象初始化



无法跳过对象初始化

  int main(){
goto lol;
int x = 0;
lol:
return 0;
}

//错误:跳转到标签'lol'
//错误:从这里
//错误:交叉初始化'int x'

如果您在对象初始化中跳过 对象的上一个实例已销毁

  struct T {
T(){cout< * T; }
〜T(){cout< 〜T; }
};

int main(){
int x = 0;

lol:
T t;
if(x ++< 5)
goto lol;
}

//输出:* 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 =;
}
}

//错误:跳转到标签'lol'
//错误:从这里
//错误: std :: string x'

...除了某些种类的对象,语言可以处理,因为它们不需要复杂的构造:

 code> int main(){
goto lol;
{
int x;
lol:
x = 0;
}
}

// OK




[n3290:6.7 / 3]:可以传入一个块, 。
从具有自动存储持续时间
的变量不在范围内的点跳转到其范围内的点不成立的程序,除非
变量具有标量类型,类类型具有一个普通的默认
构造函数和一个简单的析构函数,
之一的cv限定版本这些类型,或前面类型之一的数组,并声明
没有初始化。 [..]







3。跳跃符合其他对象的范围



同样,具有自动存储持续时间的对象不是

 

struct T {
T(){cout< * T; }
〜T(){cout< 〜T; }
};

int main(){
{
T t;
goto lol;
}

lol:
return 0;
}

// * T〜T




[n3290:6.6 / 2]:退出范围(无论如何完成),对象
具有自动存储持续时间在
中构建的范围以它们的构造的相反顺序被销毁。
[..]







结论



上述机制确保 goto 不会让你打破语言。



当然,这并不意味着你应该使用 goto 任何给定的问题,但它的意思是它不是几乎像邪恶的常见神话引导人们相信。


Is it true that goto jumps across bits of code without calling destructors and things?

e.g.

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

Won't x be leaked?

解决方案

Warning: This answer pertains to C++ only; the rules are quite different in C.


Won't x be leaked?

No, absolutely not.

It is a myth that goto is some low-level construct that allows you to override C++'s built-in scoping mechanisms. (If anything, it's longjmp that may be prone to this.)

Consider the following mechanics that prevent you from doing "bad things" with labels (which includes case labels).


1. Label scope

You can't jump across functions:

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

// error: label 'lol' used but not defined

[n3290: 6.1/1]: [..] The scope of a label is the function in which it appears. [..]


2. Object initialisation

You can't jump across object initialisation:

int main() {
   goto lol;
   int x = 0;
lol:
   return 0;
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘int x’

If you jump back across object initialisation, then 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]: [..] Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. [..]

You can't jump into the scope of an object, even if it's not explicitly initialised:

int main() {
   goto lol;
   {
      std::string x;
lol:
      x = "";
   }
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘std::string x’

... except for certain kinds of object, which the language can handle regardless because they do not require "complex" construction:

int main() {
   goto lol;
   {
      int x;
lol:
      x = 0;
   }
}

// OK

[n3290: 6.7/3]: It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer. [..]


3. Jumping abides by scope of other objects

Likewise, objects with automatic storage duration 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]: On exit from a scope (however accomplished), objects with automatic storage duration (3.7.3) that have been constructed in that scope are destroyed in the reverse order of their construction. [..]


Conclusion

The above mechanisms ensure that goto doesn't let you break the language.

Of course, this doesn't automatically mean that you "should" use goto for any given problem, but it does mean that it is not nearly as "evil" as the common myth leads people to believe.

这篇关于会使用goto泄漏变量吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆