【C++】ストリームのエラー状態を判定し、回復する方法 (fail, clear)

目次

はじめに

C++で cinifstream を使ってデータを読み込む際、ユーザーが数値を入力すべきところに文字列を入力するなど、予期せぬ入力によってストリームがエラー状態になることがあります。一度エラー状態になると、そのストリームはそれ以降の入力を全て無視してしまいます。

この問題を解決するには、

  1. ストリームのエラー状態を検知する。
  2. エラー状態をリセットする。
  3. 不正な入力データをストリームから取り除く

という3つのステップが必要です。この記事では、ストリームのエラー状態を管理するための基本的なメンバ関数と、エラーから回復するための定石的な手法を解説します。


ストリームのエラー状態

ストリームの状態は、内部的に複数のフラグで管理されています。

状態フラグメンバ関数意味
goodbit.good()エラーなしの正常な状態
eofbit.eof()入力の終端 (End-of-File) に到達した
failbit.fail()書式エラーなど、回復可能な論理エラー(例: intabcを入力)
badbit.bad()回復不能な深刻なエラー(例: ディスク障害)

if (cin) のようにストリームを直接評価すると、.fail()または.bad()trueの場合にfalseと評価されます。


エラーの検知と回復のサンプルコード

このコードは、ユーザーに数値の入力を促し、もし不正な入力(文字列など)があった場合にエラーを検知し、ストリームの状態をリセットして、再度入力を受け付けられるように回復させます。

完成コード

#include <iostream>
#include <limits> // numeric_limits

using namespace std;

int main() {
    int input_value;
    
    cout << "整数を入力してください: ";

    // >> 演算子で入力を試みる
    cin >> input_value;
    
    // 1. ストリームの状態をチェック
    //    fail()は、failbitまたはbadbitが立っている場合にtrueを返す
    if (cin.fail()) {
        cout << "不正な入力です。数値ではありません。" << endl;

        // 2. clear()で、ストリームのエラーフラグをリセットする
        cin.clear();
        
        // 3. ignore()で、入力バッファに残っている不正な入力(と改行)をクリアする
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        
        cout << "\n再度、整数を入力してください: ";
        cin >> input_value;
        
        if (cin.fail()) {
            cout << "再度入力が失敗したため、プログラムを終了します。" << endl;
            return 1;
        }
    }
    
    cout << "入力された数値は " << input_value << " です。" << endl;
    
    return 0;
}

コードの解説

1. if (cin.fail())

.fail()メンバ関数は、failbitまたはbadbitが設定されている場合にtrueを返します。int型の変数に文字列を入力しようとすると、cinは読み込みに失敗し、failbitが設定されます。これにより、エラーを検知できます。

2. cin.clear()

.clear()メンバ関数は、ストリームのエラー状態フラグをリセットし、ストリームを正常な状態(goodbit)に戻します。これを実行しない限り、ストリームはエラー状態のままで、以降の入力操作を一切受け付けません。

3. cin.ignore(...)

.clear()はエラーフラグをリセットするだけで、入力バッファに残っている不正なデータ(例: ユーザーが入力した"abc"という文字列)はそのままです。 .ignore()は、この不要なデータをバッファから捨てるためのものです。

  • numeric_limits<streamsize>::max(): 「非常に大きな数」を意味します。最大でこれだけの文字を読み飛ばします。
  • '\n': 読み飛ばしを停止する区切り文字です。

この行は、「改行文字 \n が現れるまで、または非常に多くの文字を読み込むまで、バッファの内容を無視しなさい」という意味になり、現在の行の不正な入力を一掃できます。


まとめ

今回は、C++のストリームにおけるエラーハンドリングの基本を解説しました。

  1. .fail() で、入力エラーが発生したかを検知する。
  2. .clear() で、ストリームのエラー状態をリセットする。
  3. .ignore() で、入力バッファに残った不正なデータをクリアする。

この「検知 → リセット → クリア」の3ステップが、ユーザーの不正な入力などからプログラムを回復させ、堅牢な入力処理を実装するための定石的な手法です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次