会使用goto泄漏变量吗?

Lig*_*ica 91 c++ goto

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标签)做"坏事" .


1.标签范围

你不能跳过功能:

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]:[..]标签的范围是它出现的功能.[..]


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’
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限定版本,或者前面类型之一的数组,并且在没有初始化程序的情况下声明.[..]


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

同样,自动存储时间的对象没有 "泄露"时,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用于任何给定的问题,但它确实意味着它不像普通神话引导人们相信的那样"邪恶".

  • 很好地报道了一个常见的误解.添加了+1和FAQ标签. (17认同)
  • @Daniel:问题和答案都是关于C++的,但公平点.也许我们可以有另一个FAQ消除C和C++相同的神话;) (13认同)
  • 哇,我刚刚假设C++的语义被goto打破了,但是他们出乎意料地理智!很好的答案. (12认同)
  • 你可能会注意到C并没有阻止所有这些危险的事情发生. (8认同)
  • @Tomalak:我认为我们在这里不同意.在SO上给出的许多答案都在某处明确记录.我只是指出,C程序员可能很想看到这个答案,并假设如果它在C++中工作,它应该在C中类似地工作. (3认同)
  • @Daniel:根据记录,与 C 的这种差异在兼容性部分“[n3290:C.1.5]”中明确表示。 (2认同)
  • 您还可能希望添加所有这些跳过初始化的内容对于案例标签是相同的. (2认同)
  • 也许你可以添加一个关于如果你在初始化过程中 *up* 会发生什么的简介。 (2认同)