Menu

Оператор switch в C++: case, проваливание и break

Оператор switch в C++ простыми словами: метки case, break и проваливание (fall-through), ветка default, группировка случаев, switch по enum и подводные камни при объявлениях внутри case.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Для чего нужен switch

switch сравнивает одно значение со списком фиксированных вариантов и выполняет совпавшую ветку. Когда вы ловите себя на том, что пишете длинную цепочку if/else if, которая снова и снова проверяет одну и ту же переменную на разные константы, switch выражает это намерение яснее — и часто компилируется в более быструю таблицу переходов.

Он выполняет только проверки на равенство с константами времени компиляции для целочисленного значения. Он не умеет проверять диапазоны, сравнивать строки или комбинировать условия. Для всего этого оставайтесь на if/else.

Простой switch

Вы передаёте switch значение, а затем перечисляете метки case для интересующих вас значений. Каждая ветка заканчивается break:

Значение 3 совпадает с case 3:, поэтому выводится "Wednesday", и break выпрыгивает из switch. Ветка default — это универсальный случай: она выполняется, когда ни один case не совпал. Она необязательна, но включайте её, если не уверены, что обработаны все значения.

Обратите внимание, что метки case — это просто константы, за которыми следует двоеточие, а не условия. Вы пишете case 3:, но никогда case day == 3:.

break и проваливание

Это самая важная ловушка switch в C++. После того как case совпал, выполнение не останавливается на следующем case — оно продолжает идти напрямую, пока не встретит break или закрывающую скобку. Посмотрите, что происходит, когда операторы break отсутствуют:

Вы могли бы ожидать только "one". Вместо этого выводятся все четыре строки: совпадение с case 1: входит в switch в этом месте, а затем проваливается сквозь все метки ниже. Добавьте break; после каждой ветки — и вы получите единственную нужную строку. Забытый break — классический источник ошибок вида «почему мой switch выполняет слишком много кода?».

Намеренное проваливание для группировки случаев

Проваливание не всегда ошибка — это идиоматический способ заставить несколько случаев разделять одно тело. Оставьте случаи пустыми (без операторов, без break), и все они перетекут в следующий блок:

'A', 'B' и 'C' все попадают на одну строку "Pass", потому что первые два случая пусты и проваливаются в третий. Это чисто и сделано намеренно. Когда вы действительно хотите провалиться после выполнения какого-то кода, задокументируйте это комментарием — или в C++17 и более новых версиях используйте атрибут [[fallthrough]];, который сообщает компилятору «да, я так и задумал» и подавляет предупреждения о проваливании.

switch по enum

switch естественно сочетается с enum, поскольку enum — это как раз «одно из фиксированного набора значений». Компиляторы также могут предупредить вас, если вы забудете обработать один из перечислителей:

С областным enum class вы должны квалифицировать каждую метку (Direction::East). Поскольку охвачены все перечислители, default не нужен — и многие компиляторы предупредят вас, если позже вы добавите пятое направление и забудете добавить его case. Эта помощь компилятора — весомая причина предпочесть switch цепочкам if/else для enum.

Подводный камень: объявления внутри case

Нельзя объявить переменную с инициализатором в одном case и сделать её видимой во всех остальных случаях, не ограничив её область видимости. Это распространённая ошибка компиляции:

switch (x) {
    case 1:
        int n = 10;   // ошибка: переход к case 2 обходит эту инициализацию
        cout << n;
        break;
    case 2:
        cout << "two";
        break;
}

Компилятор отвергает это, потому что переход в case 2: перепрыгнул бы через инициализацию n, пока n ещё в области видимости. Решение — обернуть тело case в собственные фигурные скобки, дав переменной отдельный блок:

Каждый раз, когда case нуждается в собственной локальной переменной, заключайте его в фигурные скобки. Это также не даёт переменной «протечь» в случаи ниже.

Далее: цикл for

switch и if позволяют вашей программе выбрать, какой код выполнить один раз. Но большая часть работы — это делать одно и то же много раз: считать, перебирать список, повторять, пока не изменится условие. Цикл for — рабочая лошадка для этого, и это следующая страница.

Часто задаваемые вопросы

Когда в C++ использовать switch вместо if-else?

Используйте switch, когда сравниваете одно целочисленное значение с множеством фиксированных, постоянных вариантов — например, пунктом меню, номером дня или значением enum. Это читается яснее, чем длинная лестница if/else if, и позволяет компилятору оптимизировать ветвление. Оставайтесь на if/else, когда условия включают диапазоны (x > 10), значения с плавающей точкой, строки или несколько переменных — switch ничего из этого не умеет.

Зачем нужен break в операторе switch в C++?

Как только case совпадает, C++ продолжает выполнять следующие случаи, пока не встретит break или конец switch. Это называется проваливанием (fall-through). break его останавливает. Забытый break — классическая ошибка: вы совпадаете с case 1: и случайно выполняете ещё и код для case 2, case 3 и default.

По каким типам можно делать switch в C++?

Только по целочисленным типам или перечислениям: int, char, short, long, bool, областной/безобластной enum и всё, что приводится к одному из них. Нельзя сделать switch по double, float или std::string — для них используйте if/else. Каждая метка case должна быть константой времени компиляции.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ