为什么这段代码片段运行良好
void foo(int i)
{
switch(i) {
case 1:
{
X x1;
break;
}
case 2:
X x2;
break;
}
}
而下面给出了编译错误('case'标签跳过'x1'的初始化)?
void foo(int i)
{
switch(i) {
case 1:
X x1;
break;
case 2:
X x2;
break;
}
}
据我所知,使用大括号引入了一个新的范围,因此在我们打开它的开头大括号之前,不会为x1分配存储空间。但x2仍然在一个案例标签内初始化,没有括号。这不应该是一个错误吗?
我认为在两个代码片段
中都可以有条件地跳过x2的初始化答案 0 :(得分:7)
1:有效
case 1:
{
X x1;
break;
}
如果没有达到条件,x1
不能被任何其他语句使用,因此不会出现运行时错误。 x1
并不试图在大括号外存在。
2:无效
switch(i) {
case 1:
X x1; //don't break
i = 2;
...
...
...
case 2:
x1.someOperation()
}
在上文中,如果i
最初为2
,则会在构建对象的x1.someOperation()
之前点击X x1
。
如果允许编译,它会抛出运行时错误,具体取决于情况:1 是否在2之前执行,(对象是建造)。因此,编译器不允许它。
普通旧数据类型允许使用相同的内容,不能具有用户定义的构造函数。
答案 1 :(得分:4)
请注意,仅当X
为非POD时才会出现错误。如果X
是POD,那么您将不会收到任何错误(当您不使用大括号时)。
如果是非POD,则不能跳过在同一范围内声明的变量的初始化。当你不使用大括号时会导致编译错误,因为switch
允许你跳过这些变量的初始化,但同时它使它们可以在所有变量中使用它下方的case
标签。这很危险。
沿着这一行思考:如果i
是2
,则控件将直接跳转到第二个case
而不初始化x1
,然后您就可以在第二种情况下使用x1
,即使它未初始化。这没有意义。因此,该语言要求它是一个错误。
顺便说一下,要了解POD和非POD是什么,请参阅以下主题:
答案 2 :(得分:2)
一般的想法是每个case
不是一个孤立的范围:case 2
下的代码可以引用x1
变量,因为它之前已在同一范围内声明(即:整个switch
块:当然,它不会被初始化,并且会导致错误。
添加花括号实际上是在分割每个case
的范围,允许您在case 1
中声明无法在其外部引用的变量。
答案 3 :(得分:0)
在条件语句中创建变量不是一个好主意。我建议您在switch
语句之外创建变量,然后根据i
上的条件将值赋值给它:
void foo(int i) {
X x1;
switch(i) {
case 1:
x1 = ...;
break;
case 2:
x1 = ...;
break;
}
}
答案 4 :(得分:0)
在失败的版本中,x1
的声明在case 2:
标签之后的几行之前不会超出范围。那就是问题所在。 x2
的声明是可以的,因为声明与其范围的结尾之间没有case
标签。