'goto label'跳过'unused'的初始化 - 为什么我为std :: string而不是int?

时间:2014-04-04 13:17:20

标签: c++ visual-studio compiler-errors goto

我在某些代码中遇到了这个错误,经过一些实验后我偶然发现了这个奇怪的问题 - 我得到的是std::string,但不是int

对于std::string,我得到error C2362: initialization of 'unused' is skipped by 'goto label'

{   goto label;
    std::string unused;
label:;
}

对于int 我没有收到任何错误,但是:

{   goto label;
    int unused = 10;
label:;
}

为何与众不同?是因为std::string有一个非平凡的析构函数吗?

2 个答案:

答案 0 :(得分:4)

draft C++ standard部分6.7 声明声明中包含了这一点,其中包含(强调我的):

  

可以转换为块,但不能以初始化绕过声明的方式。 从自动存储持续时间不在范围内的变量到其范围内的点跳过 87 的程序是不正确的,除非该变量具有标量类型,类类型使用普通的默认构造函数和一个简单的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始化程序的情况下声明(8.5)。

并提供以下示例:

void f() {
  // ...
  goto lx; // ill-formed: jump into scope of a
ly:
  X a = 1;
  // ...
lx:
 goto ly; // OK, jump implies destructor
          // call for a followed by construction
          // again immediately following label ly
}

虽然两种情况都会产生错误,因为在这两种情况下都绕过了初始化,但是这样就没问题了:

goto label;
      int unused ;
label:

所以Visual Studio在这里不正确,gccclang生成并且此代码出错,gcc说:

error:   crosses initialization of 'int unused'
       int unused = 10;
           ^

当然Visual Studio可以有这样的扩展名,只要他们记录它,但使用这样的扩展程序是不可移植的,正如我指出clanggcc生成一个错误。

我们可以找到一个理由,说明为什么我们不希望跳过defect report 467中的初始化,该初始化试图为本地静态变量添加相同的限制(它被拒绝):

  

[...]自动变量,如果没有显式初始化,可以有不确定的(“垃圾”)值,包括陷阱表示,[...]

答案 1 :(得分:3)

编译错误。两者都是非法的。什么不违法, 但是,是:

{
    goto label;
    int unused;
    unused = 10;
label:
    ;
}

std::string unused;int unused = 10;都有 初始化器(在。的情况下的默认构造函数) std::string),你不被允许跳来跳去 使用初始化程序的定义。跳过一个没有 初始化程序可能允许避免破坏代码:

switch ( something )
{
    int i;
case 0:
    i = x;
    // ...
    break;

case 1:
    i = y;
    //  ...
    break;
//  ...
}

我不会称这个好的代码,但我不会感到惊讶 在较旧的C中找到它,而C ++确实试图不破坏这些 的东西。