9

为什么这个代码片段运行良好

void foo(int i)
{
    switch(i) {
    case 1:
    {
        X x1;
        break;
    }
    case 2:
        X x2;
        break;
    }
}

而下面给出了编译错误('x1'的初始化被'case'标签跳过)?

void foo(int i)
{
    switch(i) {
    case 1:
        X x1;
        break;
    case 2:
        X x2;
        break;
    }
}

我知道使用大括号会引入一个新的范围,因此在我们点击它的左大括号之前不会为 x1 分配存储空间。但是 x2 仍然在不带括号的情况下在标签内初始化。这也不应该是一个错误吗?

我认为在两个代码片段中都可以有条件地跳过 x2 的初始化

4

5 回答 5

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

如果允许编译,它是否会抛出运行时错误,这取决于case:1是否在 2 之前执行(并且对象已被构造)。因此,编译器不允许这样做。


不能具有用户定义构造函数的普通旧数据类型也允许这样做。

于 2012-11-16T11:38:16.983 回答
4

请注意,只有在X非 POD 时才会出错。如果X是 POD,那么您将不会收到任何错误(当您不使用大括号时)。

在非 POD 的情况下,您不能跳过在同一范围内声明的变量的初始化。当你不使用大括号时,它会导致编译错误,因为它switch允许你跳过这些变量的初始化,但同时它使它们可以在case它下面的所有标签中使用。那很危险。

沿着这条线思考:如果i2,那么控件将case直接跳转到第二个而不初始化x1,然后你将能够x1在第二种情况下使用,即使它没有初始化。那没有意义。因此,语言要求它是错误的。


顺便说一句,要了解 POD 和非 POD 是什么,请参阅以下主题:

于 2012-11-16T11:38:40.680 回答
2

一般的想法是 eachcase不是一个孤立的范围:下面的代码case 2可以引用x1变量,因为它之前已经在同一范围内声明过(即:整个switch块):当然,它不会被初始化,它会导致错误。

添加大括号实际上是在拆分每个case的范围,允许您在其中声明case 1不能在其外部引用的变量。

于 2012-11-16T11:49:19.543 回答
0

在条件语句中创建变量不是一个好主意。我建议您在语句之外创建变量switch,然后根据条件为它赋值i

void foo(int i) {

    X x1;

    switch(i) {
        case 1:
            x1 = ...;
            break;
        case 2:
            x1 = ...;
            break;
    }
}
于 2012-11-16T11:37:35.427 回答
0

在失败的版本中,声明直到标签x1后的几行才超出范围。case 2:那就是问题所在。的声明是可以的,因为在声明和它的范围结束之间x2没有标签。case

于 2012-11-16T16:51:54.703 回答