エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

ストリームの失敗の種類、検出方法および例外の発生のさせ方について

こちらのエントリとコメントを読みながら、「ふだんはgood関数を使ってるけど、どんなときに『good』なんだろう?」と調べはじめたら。予想以上に知らないことが多かった。


>>演算子から始まって、わかったことを少しまとめてみました。

ストリームの状態を示す値について

フラグ 内容
eofbit ファイルの終端に達した
failbit 内部動作が原因で入力操作が失敗した
badbit ストリームバッファの入出力操作が失敗した
goodbit エラーなし(値としてはゼロ)


入力の失敗ではfailとbadがありうるようです。これは知らなかった。
実際に入力された文字列が、取り出そうとした型(変数の型)の値に変換できない場合はfailになるようです。

ストリームバッファは[http://cplusplus.com/reference/iostream/streambuf/:title=streambuf]を基底にするクラスで、実際にバイト列としてデータの読み書きをするところ(のはず)。

ストリームの状態を知る方法について

メンバ関数 動作
good eofbit、failbit、badbitのすべてが0ならばtrue、そうでなければfalse
bad badbitが1ならばtrue、0ならばfalse
fail failbit、badbitのどちらかあるいは両方が1ならば、両方が0ならばfalse
operator ! failbit、badbitのどちらかあるいは両方が1ならば、両方が0ならばfalse
operator void* failbit、badbitの両方が0ならば非0、どちらかあるいは両方が1ならば0

fail関数と!演算子は同じ動作です。

void*演算子は戻り値を真偽値と見たばあい、fail関数や!演算子の戻り値を反転した値になっています。

きちんと理解していないまま終端の検出にgood関数を使ってました。結果的には正しい使い方だったけれど知らずにいたらどこかではまっていそう。

ストリームの入出力が失敗したときに例外を投げる方法について

で。ストリームの入出力が失敗したばあいに例外を投げる方法もありました。


以下、サンプル。

#include <iostream>
#include <string>

int main(int, char* [])
{
    // failbitが1になったとき例外を投げるように設定
    std::cin.exceptions(std::ios::failbit);

    try
    {
        std::string name;
        int         age;

        std::cin >> name;
        std::cin >> age;

        std::cout << "name :" << name << ", age :" << age << "\n";
    }
    catch(const std::ios::failure& e)
    {
        std::cerr << "エラーった\n";
    }

    return 0;
}


実行結果。例外が投げられないばあい(「sample」は上記のコードの実行ファイル名です)。

$ ./sample
hoge 20
name :hoge, age :20
$ 


実行結果。例外が投げられた場合。

$ ./sample
20 hoge
エラーった