for文やwhile文などの繰り返し処理では、ループの実行フローをより細かく制御したい場面があります。C++には、そのような要求に応えるための3つの文、break、continue、gotoが用意されています。
break文:ループを完全に中断する
break文は、switch文だけでなく、for文、while文、do-while文といった繰り返し文の内部でも使用できます。
ループの実行中にbreak文に遭遇すると、そのループは即座に強制終了し、プログラムの実行はループの次の文へと移ります。
多重ループ(ネストループ)の中でbreakが実行された場合、終了するのはbreak文を直接含んでいる最も内側のループのみです。外側のループは中断されません。
break文のサンプルコード
この例では、複数のデータを含むコンテナを処理中に、「エラー」を示す特定のデータが見つかった時点で処理を打ち切ります。
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> dataPackets = {
"Data A", "Data B", "Data C", "ERROR_SIGNAL", "Data D", "Data E"
};
std::cout << "データ処理を開始します...\n";
// 範囲ベースforループで各データを処理
for (const auto& packet : dataPackets) {
// エラー信号を検出
if (packet == "ERROR_SIGNAL") {
std::cout << "エラー信号を検出したため、処理を中断します。\n";
break; // forループを即座に終了
}
// 通常の処理
std::cout << "処理中: " << packet << "\n";
}
std::cout << "データ処理が完了しました。\n";
return 0;
}
実行結果:
データ処理を開始します...
処理中: Data A
処理中: Data B
処理中: Data C
エラー信号を検出したため、処理を中断します。
データ処理が完了しました。
"ERROR_SIGNAL"が見つかった時点でbreakが実行され、後続の"Data D"や"Data E"は処理されずにループが終了していることがわかります。
continue文:現在の回の処理をスキップする
continue文は、break文のようにループを完全に終了させるのではなく、現在の回のループ本体の処理だけを中断します。
continue文が実行されると、ループ本体の残りの部分はスキップされ、次の繰り返し処理のステップへとジャンプします。
for文の場合: 更新処理(例:i++)へジャンプします。while,do-while文の場合: 条件式の評価へジャンプします。
continue文のサンプルコード
この例では、注文リストを処理し、在庫切れ(stock < 0)の商品があった場合はその注文をスキップ(記録だけして加算はしない)し、次の商品の処理へ移ります。
#include <iostream>
#include <vector>
int main() {
std::vector<int> orderQuantities = {10, 5, -1, 20, 8, -5, 12};
int totalShipped = 0; // 出荷合計数
std::cout << "注文処理を開始します。\n";
for (int quantity : orderQuantities) {
// 在庫切れなど、無効な注文数量を検出
if (quantity <= 0) {
std::cout << "無効な注文(数量: " << quantity << ")をスキップします。\n";
continue; // この回のループを中断し、次の要素の処理へ移る
}
// 有効な注文のみ処理
std::cout << quantity << "個の出荷を処理しました。\n";
totalShipped += quantity;
}
std::cout << "------------------------\n";
std::cout << "出荷合計数: " << totalShipped << "個\n";
return 0;
}
実行結果:
注文処理を開始します。
10個の出荷を処理しました。
5個の出荷を処理しました。
無効な注文(数量: -1)をスキップします。
20個の出荷を処理しました。
8個の出荷を処理しました。
無効な注文(数量: -5)をスキップします。
12個の出荷を処理しました。
------------------------
出荷合計数: 55個
数量が負の値のときにcontinueが実行され、totalShippedへの加算処理がスキップされていることがわかります。
goto文:指定ラベルへの無条件ジャンプ
goto文は、プログラムの実行を、同じ関数内にある指定されたラベルへと無条件にジャンプさせます。
// ... 処理 ...
goto myLabel; // myLabel へジャンプ
// ... この間の処理は実行されない ...
myLabel: // ラベルの定義
// ジャンプ先の処理
goto文の使用に関する現代的な見解
goto文はC言語から引き継がれた機能ですが、現代のC++プログラミングにおいてその使用は強く非推奨とされています。
非推奨の理由:
- 可読性の低下:
goto文を多用すると、プログラムの実行フローが予測不能になり、コードがどこから来てどこへ行くのかを追跡するのが非常に困難になります(いわゆる「スパゲッティコード」の原因)。 - 保守性の悪化: コードの構造が破壊されるため、デバッグや機能追加が格段に難しくなります。
- 代替手段の存在:
break、continue、関数、例外処理など、goto文を使わずに同じロジックをより安全で構造的に記述できる方法がC++には豊富に存在します。
goto文の限定的な使用例
goto文が例外的に許容される場面として、多重ループから一気に脱出するケースが挙げられることがあります。
#include <iostream>
int main() {
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
// 何か重大なエラー条件
if (i == 5 && j == 3) {
std::cout << "致命的な条件を検出。全てのループから脱出します。\n";
goto escape_loop; // 脱出用のラベルへジャンプ
}
std::cout << "(" << i << "," << j << ") ";
}
std::cout << "\n";
}
// ラベルは関数の末尾などに定義する
escape_loop:
std::cout << "ループ後のクリーンアップ処理。\n";
return 0;
}
ただし、この例でさえ、処理全体を関数に切り出し、return文で脱出する方が、よりクリーンで推奨される設計です。
結論として、goto文は学習目的で存在を知ることは有益ですが、実際の開発で新たに使用することは避けるべきです。
まとめ
break: ループを完全に終了させたいときに使用します。continue: 現在の回の処理のみをスキップして、次の回に進みたいときに使用します。goto: 指定した場所に強制ジャンプしますが、コードの構造を破壊するため、使用は原則として避けるべきです。
これらの制御文を適切に使い分けることで、より柔軟で効率的なループ処理を記述できます。
