switch and fallthrough
The switch statement is an alternative to a long if / else if chain when you are comparing one value against several constant alternatives. It is cleaner to read when there are four or more cases, and the compiler can often generate more efficient code for it. The key behavior that surprises beginners is fallthrough: by default, execution continues into the next case unless you explicitly break out.
Basic switch syntax
A switch takes an integer (or enum, or character) expression, jumps to the matching case label, and executes from there. Each case ends with a break statement that transfers control to the end of the switch. Without break, execution “falls through” into the next case. The optional default label matches any value that did not match any case.
int day = 3; // 1=Mon, 2=Tue, ...
switch (day)
{
case 1:
std::cout << "Monday\n";
break;
case 2:
std::cout << "Tuesday\n";
break;
case 3:
std::cout << "Wednesday\n";
break;
case 4:
std::cout << "Thursday\n";
break;
case 5:
std::cout << "Friday\n";
break;
case 6:
case 7:
std::cout << "Weekend\n"; // shared body for Saturday and Sunday
break;
default:
std::cout << "Invalid day\n";
break;
}The case 6: case 7: pattern (empty case followed immediately by the next) is intentional and idiomatic: it shares one body across multiple values. This is the only common form of intentional fallthrough.
Fallthrough — danger and intent
If you forget a break, execution falls through into the next case regardless of its label. This is the most common switch bug and produces hard-to-trace behavior. C++17 added the [[fallthrough]] attribute to mark intentional fallthrough, which silences compiler warnings and documents the intent.
int x = 1;
switch (x)
{
case 1:
std::cout << "one\n";
// BUG: missing break — falls through!
case 2:
std::cout << "two\n";
break;
case 3:
std::cout << "three\n";
break;
}
// Output: "one" then "two" — both printed even though x == 1// Intentional fallthrough — annotate with [[fallthrough]]:
switch (x)
{
case 1:
std::cout << "one\n";
[[fallthrough]]; // compiler warning suppressed; intent is clear
case 2:
std::cout << "one or two\n";
break;
}switch vs if-else — when to use each
A switch can only test a single integral or enum value against compile-time integer constants. It cannot test ranges, arbitrary expressions, or non-integer types. An if / else if chain can handle anything. The practical guideline:
Use switch when…
- →You are comparing one integer, char, or enum value against four or more constants
- →The cases are clean, disjoint, and each corresponds to a small piece of code
- →Performance matters — compilers may generate a jump table for dense switch cases
Use if/else when…
- →You need to test a range: if (score >= 80)
- →The condition is a complex expression or involves multiple variables
- →You are testing strings (std::string cannot be used in a switch)
- →There are only two or three cases — if/else is just as readable
// Good use of switch — simple menu dispatch
char choice = 'b';
switch (choice) {
case 'a': doAdd(); break;
case 'b': doRemove(); break; // executes this
case 'c': doList(); break;
default: std::cout << "Unknown command\n";
}
// switch with enum — very idiomatic
enum class Color { Red, Green, Blue };
Color c = Color::Green;
switch (c) {
case Color::Red: std::cout << "red\n"; break;
case Color::Green: std::cout << "green\n"; break;
case Color::Blue: std::cout << "blue\n"; break;
}Key rules to remember
Always end each case with break (or return) unless fallthrough is intentional
Forgetting break causes silent bugs where multiple case bodies execute. This is the most common switch mistake.
Mark intentional fallthrough with [[fallthrough]]
This C++17 attribute silences the compiler warning and signals to future readers that the missing break is deliberate, not a bug.
Always include a default case
default handles any value that did not match a case. Even if you think all values are covered, a default with an error message or assertion catches unexpected inputs.
switch can only match integer constants — not ranges, not strings
Use if/else for range comparisons (score >= 80), floating-point tests, or string comparisons.