Где поставить разрыв в выражении switch/case с блоками

Когда я использую фигурные скобки вокруг блока кода case в С++ для локализации переменных, я должен помещать break внутри или вне блока?

case FOO:  // 'break' inside
  {
    int i;
    doStuff();
    break;
  }

case BAR: // 'break' outside
  {
    int i;
    doStuff();
  }
  break;

Спасибо.

Ответы

Ответ 1

Это вопрос стиля.

Я бы поставил break за пределы закрывающей скобки, чтобы сделать его более читаемым.

Ответ 2

Вы ставите его, где хотите. Убедитесь, что вы остаетесь последовательными на протяжении всего проекта. (Лично я вынул его наружу.)

Ответ 3

Я обычно помещаю break в фигурные скобки, например:

switch (foo) {
    case bar: {
        int x = 5;
        printf("%d\n", x);
        break;
    }
    case baz: {
        // ...
        break;
    }
}

Однако, поскольку это мое правило, я могу свободно его разбить (не каламбур), когда захочу.

Ответ 4

Он должен появиться после.

Например:

switch(value)
{
   case 0:
   {
   // this ...
   // that ...
   // and the other ...
   }
   break;
}

Отредактированный текст ниже

В основном это улучшает читаемость и ремонтопригодность.

switch (value)
{
   case 0:
    // Do this...
    // Do that...
    break;
   case 1:
    //and the other...
   break;
}

и

switch (value)
{
   case 0:
    // Do this...
    // Do that...
    if (ObjectWithinScope.Type == Fault)
    break;
   case 1:
    //and the other...
   break;
}

Теперь сравните с

switch (value)
{
   case 0:
   {
    // Do this...
    // Do that...
   }
   break;
   case 1:
    //and the other...
   break;
}

и

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

Когда вы начинаете сталкиваться с случаями вложенных операторов switch, это может сильно запутать.

Просто указатель.

Теперь некоторые из вас по-прежнему задаются вопросом, что я получаю. Вот. Часть устаревшего кода перестала работать, и никто не мог понять, почему. Все это сводилось к фрагменту кода, структурированному следующим образом:

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

Потребовалось много времени, чтобы привязать этот код, но при проверке журналов изменений он был первоначально следующим:

   switch (value)
    {
       case 0:
       {
        // Do this...
        // Do that...
        if (ObjectWithinScope.Type == Fault)
            // *** A line of code was here ***
        break;
       }
       case 1:
       {
        //and the other...           
       }
       break;
    }

По общему признанию, исходный код не был согласован с самим собой, но благодаря разрыву в фигурных скобках код скомпилировался, когда одна строка кода была удалена случайно. Если разрыв был за пределами скобок, то этого не было бы.

Ответ 5

Все согласны с тем, что мы хотим четко распознаваемого различия между механизмом switch/case... и действительными действиями, выполняемыми в каждом случае.

Поэтому, если в каждом случае практически ничего не происходит (простое назначение или так), я предлагаю использовать switch как простой диспетчер и делегировать "реальные" вещи вспомогательным функциям. Это автоматически решает проблему локальных переменных case и вообще скрывает необходимость в фигурных скобках.

switch( operation ) {
  case cnegation: r = -value; break;
  case cinversion: r = 1./r; break;
  case cfaculty: { 
    double r = value; 
    while( value != 1 ) 
      r *= --value; 
  }
  break;
}

Должно получиться

switch( operation ) {
  case cnegation : r = negate (value) ; break;
  case cinversion: r = invert (value) ; break;
  case cfaculty  : r = faculty(value) ; break;
}

Ответ 6

Это действительно зависит от логики вашего кода и того, как он использует фигурные скобки, но для правильного ответа, если вы положили его внутрь, попробуйте поместить все из них внутри.

Ответ 7

По моему мнению, вы должны избегать локальных переменных и блоков в операторах switch. Также вам следует избегать длинных, сложных или даже каскадных операторов switch. Но никакого правила без исключения... Я предпочитаю писать оператор break после блока.

Ответ 8

Это не имеет большого значения, если вы и ваша команда последовательно выполняете одно и то же. Даже тогда, это не большая проблема, если разные члены команды делают это по-другому.

Я лично предпочитаю после. Причиной является то, что он дает некоторое разделение между машиной оператора switch (прыгающей, исполняющей вещи и выходом) и кодом в фигурных скобках, который исключительно связан с "выполнением" дела.

например:

switch( value )
{
    case 0:
        {
            // code here
        }
        break;

    default:
        {
            assert(!"unhandled value in switch");
        }
        break;
}

Я использую только {} для случая, если ему нужны локальные переменные, но если я использую {} для любого случая, я помещаю их во всех случаях.

Я обычно всегда определяю случай по умолчанию для утверждения, если есть какое-либо неожиданное значение. Удивительно, как часто один из этих утверждений стреляет, чтобы напомнить вам о недостающем случае.

Ответ 9

Мне не нравится вставлять какие-либо скобки в оператор switch. Лично, если это сложная операция, мне нравится включать ее в функцию. Там нет ничего более раздражающего, чем просмотр инструкции switch, где между каждым "случаем" присутствуют сотни строк кода, а кроме того, некоторые из них повторяются в разных случаях, что делает техническое обслуживание невозможным.

Например:

switch(blah)
{
 case 1:
  // do one thing
  break;

 case 2:
  doManyThings();
  break;

 default:  
  // something
  break;
}

Ответ 10

Это вопрос стиля, но я положил его после того, как понял определение:

switch (variable)
{
    case expression:
        statement;
        break;
    default:
        statement;
        break;
}

где инструкция представляет собой либо одну команду, либо блок. Разрыв разделен на этот оператор или блок. И да, я добавляю перерыв после дефолта, хотя он лишний. Я также ВСЕГДА кладет фигурные скобки вокруг инструкции. Слишком много раз я добавил еще одно выражение только для того, чтобы разорвать область. И я добавляю разрыв к умолчанию, поскольку я изменил значение по умолчанию: к выражению case: и добавил что-то после него. Оборонительное кодирование - ваш друг.

Однако я могу найти документацию для фактического определения через Microsoft как:

selection-statement:
    switch ( expression ) statement

labeled-statement:
    case constant-expression : statement
    default : statement

Которое указывает, что оно должно быть внутри.

Тем не менее, я думаю, что внешний вид более ясен с точки зрения читателей, но он, безусловно, субъективен.

Ответ 11

Поскольку стандарт не ограничивает вас выбором позиции для оператора break, вы можете выбрать все, что захотите. Лично я использую следующий стиль:

 switch ( some_var ) {
        case 1: {
            // lot of code here
        } break;
        case 2: /* one call */ break;
        case 3: /* one call */ break;
        case 4: {
            // lot of code here again
        } break;
    }

Ответ 12

Можно многое сказать по стилю использования только одного утверждения для каждого случая и никогда не использовать фигурные скобки. Например:

switch( cond ) {
default: foo(); break;
case 0: bar(); break;
case 1: baz(); break;
}

Используя этот стиль, ваш вопрос спорный.

Ответ 13

Реальный ответ: Компилятор не заботится. Это вопрос предпочтения.

Я помещаю их внутрь, например руководство по стилю google.

Если использовать фигурные скобки, мне нравится, что открывающая скобка находится в том же столбце, что и закрывающая скобка (которая отличается от google).

switch (var) {
  case 0: 
  {  
    ...      
    break;
  }
  case 1: 
  {
    ...
    break;
  }
  default: 
    assert(false);
}

Ответ 14

Моя просьба... См. ниже приведенный ниже пример.

Отступывать все случаи переключения и иметь закрывающую скобку переключателя под ключевым словом switch, точно так же, как в инструкции if. При необходимости одно и то же правило для каждого оператора case: открывайте скобки после полуколона, следующих за оператором case, и закрывайте их под ключевым словом case, затем отступайте содержимое каждого из операторов case, включая ключевое слово break.

Сохраняйте его согласованным (места для отступов и скобок) и короткими (не более 5-10 строк кода в выражении case. Сложные проекты потерпели неудачу из-за сильно отступов switch с слишком большим количеством кода в них.

    switch (number) {

        case 1:
            logFileStderr(VERBOSE, "MESSAGE: switch without brackets...\n");
            break;

        case 2: {
            logFileStderr(VERBOSE, "MESSAGE: switch with brackets...\n");
            break;
        }

        default:
            logFileStderr(VERBOSE, "WARNING: Unknown option...\n");
            break;
    }