Объявление переменных в конструкции case

Я всегда советую максимально ограничивать область видимости переменных. Это значительно упрощает сопровождение программы и предотвращает многие ошибки. Самый распространенный вариант такого ограничения — конструкция for. С ней обычно не возникает проблем. Сегодня же я хотел поговорить о конструкции switchcase

Рассмотрим пример, приведенный ниже

int foo(int var)
{
  int res = 0;  
  switch(var)
  {
    case 0: break; 
    
    case 2: int a = 5;
            res =  var + a;
            break;
    
    default: res = 5;       
  };
  
  return res; 
}

Несмотря на свою кажущуюся простоту этот пример не скомпилируется. Почему? Проблема в переменной a. Компилятор не позволяет нам объявить ее внутри блока case. И в общем-то правильно делает. Чтобы понять почему, взглянем на пример ниже.

//Какой-то код
int val;
//Какой-то код
switch(val)
{
  case 0:
  //какой-то код
  case 15: MyClass mc;
  //Какой-то код   
};
//Какой-то код, использующий переменную mc

Для переменной mc нужно вызывать конструктор. Но когда его следует вызывать? Согласно тексту примера тогда, когда переменная val будет равна 15. Но что произойдет, если это условие не выполнится? Тогда переменная mc будет использоваться без вызова соответствующего конструктора. Язык С++ проектировался так, чтобы никогда и ни при каких условиях этого не допускать. Любая переменная может использоваться только после того, как для нее будет вызван конструктор. С целью обеспечения соблюдения этого условия компилятор и выдает ошибку.

Получается, в блоке case нельзя объявлять переменные? Не совсем так. В нашем простом примере от лишней переменной вообще можно отказаться. Но давайте будем считать, что реальный пример значительно сложнее. Отказаться от дополнительной переменной нельзя. Вывести ее за пределы конструкции switch конечно можно, но не хотелось бы. Тем более что в нашем воображаемом примере она используется только внутри одного блока case. Как быть?

Нам помогут фигурные скобки. В С++ область видимости переменной начинается от места ее объявления и заканчивается первой закрывающейся фигурной скобкой того же уровня. Чтобы понять, что это значит, рассмотрим пример

//Какой-то код
{
  int a;
  //Какой-то код
}
//Здесь переменная a уже не видна

Здесь область видимости переменной a простирается до первой закрывающейся фигурной скобки. При этом сами эти скобки могут быть как частью конструкции языка (подпрограммы, цикла, ветвления и др), так и просто прописаны в коде приложения как есть. Пример ниже показывает, что подразумевается под словосочетанием «того же уровня»

//Какой-то код
{
  int a;
  //Какой-то код
  {
    //Какой-то код
    //Переменная a видна    
  }
}
//Здесь переменная a уже не видна

В этом примере первая закрывающаяся скобка никак не влияет на видимость переменной a. Она закрывает блок, расположенный «ниже» того блока, в котором объявлена переменная.

Хорошо. Вернемся к нашему исходному примеру. Ниже приводится его модифицированный вариант.

int foo(int var)
{
  int res = 0;  
  switch(var)
  {
    case 0: break; 
    
    case 2: {
              int a = 5;
              res =  var + a;
            };  
            break;
    
    default: res = 5;
  };
  
  return res; 
}

В этом варианте мы заключили переменную a в фигурные скобки. Её область видимости теперь строго ограничена так, как нам нужно. Неопределенности нет, и пример нормально компилируется.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *