我在某些代码中遇到了这个错误,经过一些实验后我偶然发现了这个奇怪的问题 - 我得到的是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
有一个非平凡的析构函数吗?
答案 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
在这里不正确,gcc
和clang
生成并且此代码出错,gcc
说:
error: crosses initialization of 'int unused'
int unused = 10;
^
当然Visual Studio
可以有这样的扩展名,只要他们记录它,但使用这样的扩展程序是不可移植的,正如我指出clang
和gcc
生成一个错误。
我们可以找到一个理由,说明为什么我们不希望跳过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 ++确实试图不破坏这些 的东西。