Почему переменные не могут быть объявлены в операторе switch? - PullRequest
873 голосов
/ 18 сентября 2008

Меня всегда удивляло это - почему вы не можете объявить переменные после метки регистра в операторе switch? В C ++ вы можете объявлять переменные практически везде (и объявление их близко к первому использованию, очевидно, хорошо), но следующее все равно не будет работать:

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

Вышеприведенное дает мне следующую ошибку (MSC):

инициализация 'newVal' пропускается меткой 'case'

Это кажется ограничением и в других языках. Почему это такая проблема?

Ответы [ 23 ]

0 голосов
/ 08 февраля 2013

Похоже, что анонимные объекты могут быть объявлены или созданы в операторе переключения регистра по той причине, что на них нельзя ссылаться и, следовательно, они не могут перейти к следующему случаю. Рассмотрим этот пример, который компилируется в 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;
}
0 голосов
/ 10 июля 2012

C ++ Стандарт имеет: Можно передавать в блок, но не так, чтобы обойти объявления с инициализацией. Программа, которая переходит от точки, в которой локальная переменная с автоматическим хранением находится вне области действия, до точки, в которой она находится в области действия, имеет неправильную форму, если переменная не имеет тип POD (3.9) и не объявлена ​​без инициализатора (8.5).

Код для иллюстрации этого правила:

#include <iostream>

using namespace std;

class X {
  public:
    X() 
    {
     cout << "constructor" << endl;
    }
    ~X() 
    {
     cout << "destructor" << endl;
    }
};

template <class type>
void ill_formed()
{
  goto lx;
ly:
  type a;
lx:
  goto ly;
}

template <class type>
void ok()
{
ly:
  type a;
lx:
  goto ly;
}

void test_class()
{
  ok<X>();
  // compile error
  ill_formed<X>();
}

void test_scalar() 
{
  ok<int>();
  ill_formed<int>();
}

int main(int argc, const char *argv[]) 
{
  return 0;
}

Код для отображения эффекта инициализатора:

#include <iostream>

using namespace std;

int test1()
{
  int i = 0;
  // There jumps fo "case 1" and "case 2"
  switch(i) {
    case 1:
      // Compile error because of the initializer
      int r = 1; 
      break;
    case 2:
      break;
  };
}

void test2()
{
  int i = 2;
  switch(i) {
    case 1:
      int r;
      r= 1; 
      break;
    case 2:
      cout << "r: " << r << endl;
      break;
  };
}

int main(int argc, const char *argv[]) 
{
  test1();
  test2();
  return 0;
}
0 голосов
/ 18 сентября 2008

newVal существует во всей области действия коммутатора, но инициализируется только при нажатии конечности VAL. Если вы создаете блок вокруг кода в VAL, все должно быть в порядке.

...