我一直在想这个问题——为什么不能在switch语句的case标签后面声明变量呢?在c++中,你可以在任何地方声明变量(并且在第一次使用时声明它们显然是一件好事),但以下仍然不能工作:

switch (val)  
{  
case VAL:  
  // This won't work
  int newVal = 42;  
  break;
case ANOTHER_VAL:  
  ...
  break;
}  

上面给了我以下错误(MSC):

'newVal'的初始化被'case'标签跳过

这在其他语言中似乎也是一个限制。为什么这是一个问题?


当前回答

整个switch语句在同一个作用域中。要解决这个问题,可以这样做:

switch (val)
{
    case VAL:
    {
        // This **will** work
        int newVal = 42;
    }
    break;

    case ANOTHER_VAL:
      ...
    break;
}

注意括号。

其他回答

整个switch语句在同一个作用域中。要解决这个问题,可以这样做:

switch (val)
{
    case VAL:
    {
        // This **will** work
        int newVal = 42;
    }
    break;

    case ANOTHER_VAL:
      ...
    break;
}

注意括号。

交换机的整个部分是一个单独的声明上下文。你不能像那样在case语句中声明变量。试试这个吧:

switch (val)  
{  
case VAL:
{
  // This will work
  int newVal = 42;
  break;
}
case ANOTHER_VAL:  
  ...
  break;
}

好的。我要澄清一下,这和申报完全没有关系。它只涉及“跳过初始化”(ISO c++ '03 6.7/3)

这里的许多帖子都提到跳过声明可能会导致变量“未被声明”。这是不对的。POD对象可以在没有初始化式的情况下声明,但它将具有不确定的值。例如:

switch (i)
{
   case 0:
     int j; // 'j' has indeterminate value
     j = 0; // 'j' set (not initialized) to 0, but this statement
            // is jumped when 'i == 1'
     break;
   case 1:
     ++j;   // 'j' is in scope here - but it has an indeterminate value
     break;
}

当对象是非pod或聚合时,编译器会隐式地添加一个初始化式,因此不可能跳过这样的声明:

class A {
public:
  A ();
};

switch (i)  // Error - jumping over initialization of 'A'
{
   case 0:
     A j;   // Compiler implicitly calls default constructor
     break;
   case 1:
     break;
}

这种限制并不局限于switch语句。使用'goto'跳过初始化也是一个错误:

goto LABEL;    // Error jumping over initialization
int j = 0; 
LABEL:
  ;

一个小细节是,这是c++和C之间的区别。在C中,跳过初始化并不是错误。

正如其他人所提到的,解决方案是添加一个嵌套块,以便变量的生命周期被限制为单个case标签。

我相信手头的问题是,这是声明被跳过,你试图在其他地方使用var,它不会被声明。

匿名对象似乎可以在switch case语句中声明或创建,因为它们不能被引用,因此不能进入下一个case。考虑这个例子是在GCC 4.5.3和Visual Studio 2008上编译的(可能是一个遵从性问题,所以请专家们权衡一下)

#include <cstdlib>

struct Foo{};

int main()
{
    int i = 42;

    switch( i )
    {
    case 42:
        Foo();  // Apparently valid
        break;

    default:
        break;
    }
    return EXIT_SUCCESS;
}