会使用goto泄漏变量吗?

时间:2011-09-07 13:47:24

标签: c++ goto

goto跳过代码而不调用析构函数和事物是真的吗?

e.g。

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

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

不会x被泄露吗?

1 个答案:

答案 0 :(得分:206)

警告:此答案仅适用于C ++ ; C中的规则完全不同。


  

不会x被泄露吗?

不,绝对没有。

goto是一个允许你覆盖C ++的内置作用域机制的低级构造,这是一个神话。 (如果有的话,那可能是longjmp。)

考虑以下机制,阻止您使用标签(包括case标签)做“坏事”。


1。标签范围

你不能跳过功能:

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’

如果你跨对象初始化跳,那么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限定版本   声明这些类型或前面类型之一的数组   没有初始化器。 [..]


3。跳跃遵守其他对象的范围

同样,具有自动存储持续时间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来解决任何问题,但确实意味着它不像“邪恶”那样共同的神话引导人们相信。