C++のswitch文を書いていて、「breakって毎回書かないとダメなの?」「忘れたらどうなるの?」と疑問に思ったことはありませんか?
実は、breakを忘れると次のcaseまで実行されてしまい、予期しないバグの原因になります。一方で、この挙動を意図的に使うテクニックもあります。
この記事を読み終えると、あなたはbreakの役割とフォールスルーの仕組みを完全に理解できると思いますので、ぜひ最後まで読んでいただけると嬉しいです。
breakとは?
breakとは、switch文やループから抜け出すためのキーワードです。
switch文では、breakを書かないと次のcaseにそのまま流れてしまいます。これをフォールスルー(fall through)と呼びます。
まずは、breakがある場合とない場合を比較してみましょう。
breakがある場合(正常動作)
▼main.cpp
#include <iostream>
int main() {
int cmd = 2;
switch (cmd) {
case 1:
std::cout << "新規作成\n";
break; // ← ここでswitch文から抜ける
case 2:
std::cout << "開く\n";
break; // ← ここでswitch文から抜ける
case 3:
std::cout << "保存\n";
break;
default:
std::cout << "無効なコマンド\n";
}
std::cout << "処理完了\n";
return 0;
}実行結果
開く
処理完了
case 2の処理だけが実行され、breakでswitch文から抜けて次の行に進みます。
breakがない場合(フォールスルー発生)
では、breakを書き忘れるとどうなるでしょうか?
▼main.cpp
#include <iostream>
int main() {
int cmd = 2;
switch (cmd) {
case 1:
std::cout << "新規作成\n";
// breakがない!
case 2:
std::cout << "開く\n";
// breakがない!
case 3:
std::cout << "保存\n";
break;
default:
std::cout << "無効なコマンド\n";
}
std::cout << "処理完了\n";
return 0;
}実行結果
開く
保存
処理完了
case 2だけでなく、case 3まで実行されてしまいました!
これがフォールスルーです。breakがないと、条件に関係なく次のcaseに流れ込んでしまいます。
フォールスルーの危険性
フォールスルーは意図しないバグの原因になります。
▼main.cpp
#include <iostream>
int main() {
int level = 2;
int damage = 0;
switch (level) {
case 1:
damage = 10;
// breakを忘れた!
case 2:
damage = 20;
// breakを忘れた!
case 3:
damage = 30;
break;
}
std::cout << "ダメージ: " << damage << "\n";
return 0;
}実行結果
ダメージ: 30
level = 2なのに、ダメージが30になってしまいました。
本来はdamage = 20で終わるはずが、breakがないためcase 3も実行され、damage = 30で上書きされてしまったのです。
【重要】私が実際にbreakで困った体験談
体験談1: ゲームのメニューが暴走した
勉強として「RPGのメニュー画面」を作っていた時のことです。以下のようなコードを書きました。
int choice = 1; // 1=アイテム, 2=装備, 3=ステータス
switch (choice) {
case 1:
std::cout << "アイテムを開く\n";
// breakを忘れた!
case 2:
std::cout << "装備を開く\n";
// breakを忘れた!
case 3:
std::cout << "ステータスを開く\n";
break;
}「アイテム」を選んだのに、「アイテムを開く」「装備を開く」「ステータスを開く」すべてが実行されてしまいました。
アイテムを開く
装備を開く
ステータスを開く
デバッグに30分以上かかり、原因がbreakの書き忘れだと気づいた時は絶望しました。この経験から、switch文ではbreakを必ず書く習慣がつきました。
体験談2: 敵のAIが全パターン実行してしまった
個人開発でアクションゲームを作っていた時、敵のAI行動を以下のように実装しました。
int aiState = 1; // 1=巡回, 2=追跡, 3=攻撃
switch (aiState) {
case 1:
std::cout << "巡回中...\n";
// breakを書き忘れた!
case 2:
std::cout << "プレイヤーを追跡!\n";
// breakを書き忘れた!
case 3:
std::cout << "攻撃!\n";
break;
}敵が「巡回」状態なのに、「巡回→追跡→攻撃」すべてが1フレームで実行されてしまいました。
巡回中...
プレイヤーを追跡!
攻撃!
テストプレイヤーから「敵がワープして攻撃してくる」とバグ報告が届き、原因を調べたらbreakの書き忘れでした。switch文は1文字のミスで大きなバグになると痛感しました。
フォールスルーを意図的に使う場合
フォールスルーは危険ですが、意図的に使うと便利な場面もあります。
例1: 複数のcaseで同じ処理をする
▼main.cpp
#include <iostream>
int main() {
char grade = 'B';
switch (grade) {
case 'A':
case 'B':
case 'C':
std::cout << "合格\n";
break;
case 'D':
case 'F':
std::cout << "不合格\n";
break;
default:
std::cout << "無効な成績\n";
}
return 0;
}実行結果
合格
これは「A, B, C のどれかなら合格」という意味です。フォールスルーを活用した正しい書き方です。
例2: 曜日判定
▼main.cpp
#include <iostream>
int main() {
int dayOfWeek = 6; // 1=月, 2=火, ..., 6=土, 7=日
switch (dayOfWeek) {
case 1:
case 2:
case 3:
case 4:
case 5:
std::cout << "平日\n";
break;
case 6:
case 7:
std::cout << "週末\n";
break;
default:
std::cout << "無効な曜日\n";
}
return 0;
}実行結果
週末
このように、複数のcaseで同じ処理をしたい時はフォールスルーが便利です。
よくある失敗例と対処法
失敗例1: 最後のcaseだけbreakを書き忘れた
症状: 最後のcaseからdefaultに流れてしまう
原因: 最後のcaseにもbreakが必要
対処法: すべてのcaseにbreakを書く習慣をつける
// NG
switch (cmd) {
case 1:
std::cout << "処理1\n";
break;
case 2:
std::cout << "処理2\n";
// breakがない!
default:
std::cout << "無効\n"; // ← ここも実行される
}
// OK
switch (cmd) {
case 1:
std::cout << "処理1\n";
break;
case 2:
std::cout << "処理2\n";
break; // ← 必ず書く
default:
std::cout << "無効\n";
}失敗例2: フォールスルーを使ったがコメントがない
症状: 他の人が「breakの書き忘れ」だと勘違いする
原因: 意図的なフォールスルーだとわからない
対処法: コメントで明示する
// NG(意図が不明)
switch (grade) {
case 'A':
case 'B':
std::cout << "合格\n";
break;
}
// OK(コメントで明示)
switch (grade) {
case 'A':
case 'B': // フォールスルー: AとBは同じ処理
std::cout << "合格\n";
break;
}
// または [[fallthrough]] 属性を使う(C++17以降)
switch (grade) {
case 'A':
[[fallthrough]]; // 意図的なフォールスルー
case 'B':
std::cout << "合格\n";
break;
}失敗例3: defaultにbreakを書いていない
症状: defaultの後にコードがあると実行されてしまう
原因: defaultも他のcaseと同じくフォールスルーする
対処法: defaultにもbreakを書く(またはreturnで終える)
// NG
switch (cmd) {
case 1:
std::cout << "処理1\n";
break;
default:
std::cout << "無効\n";
// breakがない!
}
std::cout << "ここも実行される\n"; // switch外だが、defaultから流れる
// OK
switch (cmd) {
case 1:
std::cout << "処理1\n";
break;
default:
std::cout << "無効\n";
break; // ← 書く
}
std::cout << "正常に実行\n";breakとreturnの違い
switch文では、breakの代わりにreturnを使うこともできます。
▼main.cpp
#include <iostream>
int getPrice(int itemID) {
switch (itemID) {
case 1:
return 100; // breakの代わりにreturn
case 2:
return 200;
case 3:
return 300;
default:
return 0;
}
}
int main() {
std::cout << "価格: " << getPrice(2) << "円\n";
return 0;
}実行結果
価格: 200円
returnは関数自体を終了するため、breakよりも強力です。関数内のswitch文ならreturnを使う方がシンプルです。
break vs return 比較表
| 比較項目 | break | return |
|---|---|---|
| 動作 | switch文から抜ける | 関数自体を終了 |
| 使える場所 | switch, ループ | 関数内のどこでも |
| switch後の処理 | 実行される | 実行されない |
| 値の返却 | 不可 | 可能 |
| おすすめ | switch後に処理がある時 | 値を返す関数の中 |
注意点
- ⚠️ break忘れは頻出バグ: コンパイラは警告を出さないことが多い
- ⚠️ すべてのcaseにbreakを書く: 最後のcaseもdefaultも例外なし
- ⚠️ 意図的なフォールスルーはコメント必須:
[[fallthrough]]や// フォールスルーと明示 - ⚠️ returnで代用可能: 関数内ならreturnの方がシンプル
- ⚠️ デバッグ時は真っ先に疑う: 予期しない動作ならbreakを確認
まとめ
breakの重要性をまとめます。
- ✅ breakがないと次のcaseも実行される(フォールスルー)
- ✅ フォールスルーは意図しないバグの原因になる
- ✅ すべてのcaseにbreakを書くのが基本
- ✅ 複数caseで同じ処理をする時はフォールスルーが便利
- ✅ 意図的なフォールスルーはコメント必須(
[[fallthrough]]推奨) - ✅ 関数内ならreturnで代用可能
- ✅ デバッグ時は真っ先にbreakを疑う
これでbreakの役割とフォールスルーの仕組みはバッチリですね!
switch文を書く時は、必ずbreakを書く習慣をつけましょう。
ここまで読んでくださり、ありがとうございました。
この記事が皆様の学習に役立てば幸いです。

