【问题标题】:Will using goto leak variables?会使用 goto 泄漏变量吗?
【发布时间】:2011-11-12 04:37:43
【问题描述】:

goto 在不调用析构函数和其他东西的情况下跳过代码位是真的吗?

例如

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

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

x不会泄露吗?

【问题讨论】:

  • 相关:stackoverflow.com/questions/1258201/…(但我想从头开始,干净利落!)
  • "Won't x be leaked" 是什么意思? x 的类型是内置数据类型。你为什么不选择一个更好的例子?
  • @Nawaz:这个例子是完美的。几乎每次我与某人谈论goto 时,他们都认为即使是自动存储持续时间变量也会以某种方式“泄露”。你和我所知道的完全不重要。
  • @David:我同意当变量具有非平凡的析构函数时这个问题更有意义......我查看了 Tomalak 的答案并确实找到了这样一个例子。此外,虽然int 不能泄漏,但它可以被泄漏。例如:void f(void) { new int(5); } 泄漏 int
  • 为什么不将问题更改为“在给出的示例中,代码执行路径是否会在不清除堆栈和其他函数返回功能的情况下从 f() 转移到 main()?会是否需要调用析构函数有关系吗?在C语言中是否相同?这样既能保持问题的意图,又能避免可能的误解?

标签: c++ goto


【解决方案1】:

警告:此答案仅适用于 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,但它确实意味着它不像常见的神话那样“邪恶”引导人们相信。

【讨论】:

  • 您可能会注意到,C 语言并不能阻止所有这些危险事情的发生。
  • @Daniel:问题和答案是关于 C++ 的,但很公平。也许我们可以有另一个常见问题解答来消除 C 和 C++ 相同的神话;)
  • @Tomalak:我不认为我们在这里存在分歧。 SO上给出的许多答案都明确记录在某处。我只是指出,C 程序员可能很想看到这个答案并假设如果它在 C++ 中工作,它应该在 C 中类似地工作。
  • 您可能还想补充一点,所有这些跳过初始化的东西对于案例标签都是一样的。
  • 哇,我刚刚假设 C++ 的语义被破坏了 goto,但他们出奇的理智!很好的答案。
猜你喜欢
  • 2010-11-18
  • 2010-10-25
  • 2023-03-28
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 1970-01-01
相关资源
最近更新 更多