我一直在想这个问题——为什么不能在switch语句的case标签后面声明变量呢?在c++中,你可以在任何地方声明变量(并且在第一次使用时声明它们显然是一件好事),但以下仍然不能工作:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
上面给了我以下错误(MSC):
'newVal'的初始化被'case'标签跳过
这在其他语言中似乎也是一个限制。为什么这是一个问题?
一个switch块不同于一连串的if/else if块。我很惊讶没有其他答案能解释清楚。
考虑下面的switch语句:
switch (value) {
case 1:
int a = 10;
break;
case 2:
int a = 20;
break;
}
这可能令人惊讶,但编译器不会将其视为简单的if/else if。它将生成以下代码:
if (value == 1)
goto label_1;
else if (value == 2)
goto label_2;
else
goto label_end;
{
label_1:
int a = 10;
goto label_end;
label_2:
int a = 20; // Already declared !
goto label_end;
}
label_end:
// The code after the switch block
case语句被转换为标签,然后用goto调用。括号创建了一个新的作用域,现在很容易看出为什么不能在一个开关块中声明两个具有相同名称的变量。
它可能看起来很奇怪,但是支持fallthrough是必要的(也就是说,不使用break让执行继续到下一个case)。
您不能这样做,因为case标签实际上只是包含块的入口点。
达夫的装置最清楚地说明了这一点。以下是一些来自维基百科的代码:
strcpy(char *to, char *from, size_t count) {
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
请注意大小写标签是如何完全忽略块边界的。是的,这是邪恶的。但这就是为什么您的代码示例不起作用。跳转到case标签与使用goto相同,因此不允许跳过带有构造函数的局部变量。
正如其他几张海报所指出的那样,你需要放入自己的方块:
switch (...) {
case FOO: {
MyObject x(...);
...
break;
}
...
}