Menu

Instrukcja switch w C++: case, fall-through i break

Instrukcja switch w C++ krok po kroku: etykiety case, break i przechodzenie do kolejnych przypadków (fall-through), gałąź default, grupowanie przypadków, switch na typach enum oraz pułapki z deklaracjami wewnątrz case.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Do czego służy switch

switch porównuje jedną wartość z listą stałych opcji i wykonuje pasującą gałąź. Jeśli łapiesz się na pisaniu długiego łańcucha if/else if, który w kółko sprawdza tę samą zmienną z różnymi stałymi, switch wyraża ten zamiar czytelniej i często kompiluje się do szybszej tablicy skoków.

Wykonuje wyłącznie sprawdzenia równości ze stałymi znanymi w czasie kompilacji, na wartości typu całkowitoliczbowego. Nie sprawdzi zakresów, nie porówna napisów i nie połączy warunków. W każdym z tych przypadków zostań przy if/else.

Podstawowy switch

Przekazujesz do switch wartość, a potem wypisujesz etykiety case dla interesujących cię wartości. Każda gałąź kończy się instrukcją break:

Wartość 3 pasuje do case 3:, więc wypisuje się "Wednesday", a break wyskakuje z instrukcji switch. Gałąź default łapie wszystko inne: wykonuje się, gdy żaden case nie pasuje. Jest opcjonalna, ale dodawaj ją, chyba że masz pewność, że obsłużono każdą wartość.

Zauważ, że etykiety case to gołe stałe z dwukropkiem, a nie warunki. Piszesz case 3:, nigdy case day == 3:.

break i fall-through

To najważniejsza pułapka instrukcji switch w C++. Po dopasowaniu case wykonanie nie zatrzymuje się na następnym case: biegnie dalej, aż trafi na break albo zamykającą klamrę. Zobacz, co się dzieje, gdy brakuje instrukcji break:

Można by się spodziewać samego "one". Zamiast tego wypisują się wszystkie cztery linie: dopasowanie case 1: wchodzi do instrukcji switch w tym miejscu, a potem przechodzi przez każdą etykietę poniżej. Dodaj break; po każdej gałęzi, a dostaniesz tylko tę jedną linię, o którą chodziło. Brak break to klasyczne źródło błędów typu "dlaczego mój switch wykonuje za dużo kodu?".

Celowe fall-through do grupowania przypadków

Fall-through nie zawsze jest błędem: to idiomatyczny sposób, żeby kilka przypadków dzieliło jedno ciało. Zostaw przypadki puste (bez instrukcji i bez break), a wszystkie przejdą do następnego bloku:

'A', 'B' i 'C' trafiają do tej samej linii "Pass", bo dwa pierwsze przypadki są puste i przechodzą do trzeciego. To czysty i zamierzony kod. Gdy naprawdę chcesz przejść dalej po wykonaniu jakiegoś kodu, opisz to komentarzem albo, od C++17, atrybutem [[fallthrough]];, który mówi kompilatorowi "tak, tak miało być" i wycisza ostrzeżenia o fall-through.

switch na typach enum

switch naturalnie współpracuje z typami wyliczeniowymi, bo enum to właśnie "jedna z ustalonego zbioru wartości". Kompilatory potrafią też ostrzec, gdy zapomnisz obsłużyć któryś z enumeratorów:

Przy enum class z zakresem musisz kwalifikować każdą etykietę (Direction::East). Wszystkie enumeratory są obsłużone, więc default nie jest potrzebny, a wiele kompilatorów ostrzeże cię, gdy później dodasz piąty kierunek i zapomnisz o jego przypadku. Ta pomoc kompilatora to ważny powód, by przy typach enum wybierać switch zamiast łańcuchów if/else.

Pułapka: deklaracje wewnątrz case

Nie możesz zadeklarować zmiennej z inicjalizatorem w jednym przypadku i mieć jej widocznej w pozostałych bez nadania jej własnego zakresu. To częsty błąd kompilacji:

switch (x) {
    case 1:
        int n = 10;   // błąd: skok do case 2 pomija tę inicjalizację
        cout << n;
        break;
    case 2:
        cout << "two";
        break;
}

Kompilator to odrzuca, bo wejście do case 2: pominęłoby inicjalizację n, podczas gdy n nadal byłoby w zasięgu. Rozwiązanie to otoczenie ciała przypadku własnymi klamrami, dzięki czemu zmienna dostaje osobny blok:

Gdy case potrzebuje własnej zmiennej lokalnej, daj mu klamry. Dzięki temu zmienna nie wycieka też do przypadków poniżej.

Dalej: pętla for

switch i if pozwalają programowi jednorazowo wybrać, który kod wykonać. Wiele zadań wymaga jednak robienia tego samego wiele razy: liczenia, przechodzenia po liście, powtarzania, aż zmieni się warunek. Do tego służy pętla for i to ona jest tematem następnej strony.

Najczęściej zadawane pytania

Kiedy używać switch zamiast if-else w C++?

Używaj switch, gdy porównujesz jedną wartość całkowitoliczbową z wieloma stałymi opcjami, na przykład wyborem z menu, numerem dnia albo wartością enum. Czyta się to wyraźniej niż długą drabinkę if/else if, a kompilator może zoptymalizować wybór gałęzi. Zostań przy if/else, gdy warunki obejmują zakresy (x > 10), liczby zmiennoprzecinkowe, napisy lub kilka zmiennych: switch nie obsłuży żadnego z tych przypadków.

Po co jest break w instrukcji switch w C++?

Gdy któryś case zostanie dopasowany, C++ wykonuje kolejne przypadki, dopóki nie trafi na break albo na koniec instrukcji switch. To zjawisko nazywa się fall-through (przechodzenie dalej). break je zatrzymuje. Brak break to klasyczny błąd: dopasowujesz case 1: i przypadkiem wykonujesz też kod dla case 2, case 3 oraz default.

Na jakich typach można używać switch w C++?

Tylko na typach całkowitych i wyliczeniowych: int, char, short, long, bool, enum z zakresem lub bez oraz na wszystkim, co się do nich konwertuje. Nie użyjesz switch na double, float ani std::string: w takich przypadkach sięgnij po if/else. Każda etykieta case musi być stałą znaną w czasie kompilacji.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ