switch文でbreakを忘れて後続のcaseまで実行されるバグ
switch文の各case節末尾にbreakを書き忘れ、該当したcase以降のすべての節が続けて実行されてしまうバグです。
なぜエラーが出ないのか
出力: Mon\nTue
(エラーなし)- C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: Mon\nTue- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 int main() { 3 int day = 1; 4 switch (day) { 5 case 1: 6 std::cout << "Mon" << std::endl; 7 ^ 8 case 2: 9 std::cout << "Tue" << std::endl; 10 break; 11 case 3: 12 std::cout << "Wed" << std::endl; 13 break; 14 } 15 return 0; 16 }
case 1の末尾にbreakが無いため、一致したcase 1の処理が終わったあとも止まらずcase 2まで続けて実行されてしまいます。
直し方: (空) を break; にします。
パターン2
1 #include <iostream> 2 int main() { 3 int level = 1; 4 switch (level) { 5 case 1: 6 std::cout << "low" << std::endl; 7 ^ 8 case 2: 9 std::cout << "mid" << std::endl; 10 break; 11 case 3: 12 std::cout << "high" << std::endl; 13 break; 14 } 15 return 0; 16 }
case 1の末尾にbreakが無いため、一致したcase 1の処理が終わったあとも止まらずcase 2まで続けて実行されてしまいます。
直し方: (空) を break; にします。
パターン3
1 #include <iostream> 2 int main() { 3 int grade = 1; 4 switch (grade) { 5 case 1: 6 std::cout << "A" << std::endl; 7 ^ 8 case 2: 9 std::cout << "B" << std::endl; 10 break; 11 case 3: 12 std::cout << "C" << std::endl; 13 break; 14 } 15 return 0; 16 }
switchはbreakに出会うかブロックの終わりに達するまで、上から下へすべての文を実行し続けます(フォールスルー)。
直し方: (空) を break; にします。
パターン4
1 #include <iostream> 2 int main() { 3 int mode = 1; 4 switch (mode) { 5 case 1: 6 std::cout << "start" << std::endl; 7 ^ 8 case 2: 9 std::cout << "run" << std::endl; 10 break; 11 case 3: 12 std::cout << "stop" << std::endl; 13 break; 14 } 15 return 0; 16 }
case 1の末尾にbreakが無いため、一致したあともcase 2まで続けて実行されてしまいます。
直し方: (空) を break; にします。
パターン5
1 #include <iostream> 2 int main() { 3 int step = 1; 4 switch (step) { 5 case 1: 6 std::cout << "first" << std::endl; 7 ^ 8 case 2: 9 std::cout << "second" << std::endl; 10 break; 11 case 3: 12 std::cout << "third" << std::endl; 13 break; 14 } 15 return 0; 16 }
switchはbreakに出会うかブロックの終わりに達するまで実行し続けます。
直し方: (空) を break; にします。
よくある誤解
「一致したcaseの中身だけが実行される」というのは誤解です。C++のswitchはbreakに出会うかswitchブロックの終わりに達するまで、上から下へすべての文を実行し続けます(フォールスルー)。
実務での勘所
意図的なフォールスルーであることをコンパイラと読み手の両方に伝える手段として、C++17から[[fallthrough]];という標準の属性が使えるようになりました。caseの最後にこれを書いておけば、-Wimplicit-fallthroughのような警告を有効にしていても「これは意図的です」と伝わり警告されなくなります。C++17より前はコンパイラごとの独自拡張に頼る必要がありましたが、現在は標準の書き方に統一されています。