28

rdstate()、、、、およびフラグgood()が 、bad()、およびでどのように表現されているかに、eof()私は繰り返し困惑しています。fail()basic_ios::operator!operator booloperator void*

誰かが私を悲惨な状態から解放し、これを説明してくれませんか?

4

2 に答える 2

24

エラー状態を示す 3 つのフラグがあります。

  • badbitストリームに何か問題が発生したことを意味します。バッファ エラーまたはストリームにデータを供給しているもののエラーである可能性があります。このフラグが設定されている場合、ストリームをもう使用しない可能性があります。

  • failbitは、ストリームからの抽出または読み取り (または出力ストリームの書き込みまたは挿入) が失敗したことを意味し、その失敗に注意する必要があります。

  • eofbit入力ストリームが最後に達し、読み取るものが残っていないことを意味します。これは、最後に達した入力ストリームから読み取ろうとした後にのみ設定されることに注意してください (つまり、存在しないデータを読み取ろうとしたためにエラーが発生した場合に設定されます)。

またfailbit、EOF に到達する多くの操作によって設定される場合もあります。たとえば、ストリームに空白しか残っていないときに を読み取ろうとするintと、両方とも EOF に達し、 の読み取りに失敗するintため、両方のフラグが設定されます。

関数はfail()テストしbadbit || failbitます。

関数はgood()テストし!(badbit || failbit || eofbit)ます。つまり、どのビットも設定されていない場合、ストリームは良好です。

ios::clear()メンバー関数を使用してフラグをリセットできます。これにより、任意のエラー フラグを設定できます。デフォルト (引数なし) では、3 つのフラグすべてがクリアされます。

ストリームはオーバーロードしませんoperator bool()operator void*()は、安全な bool イディオムのやや壊れたバージョンを実装するために使用されます。この演算子オーバーロードは、badbitorfailbitが設定されている場合は null を返し、それ以外の場合は null 以外を返します。これを使用して、抽出の成功をループまたはその他の制御フロー ステートメントの条件としてテストするイディオムをサポートできます。

if (std::cin >> x) {
    // extraction succeeded
}
else {
    // extraction failed
}

オーバーoperator!()ロードはoperator void*();の反対です。orが設定されてtrueいる場合は返され、そうでない場合は返されます。オーバーロードはもう必要ありません。演算子のオーバーロードが完全かつ一貫してサポートされる前にさかのぼります (sbi の質問「なぜ std::basic_ios が単項論理否定演算子をオーバーロードするのですか?」を参照)。badbitfailbitfalseoperator!()

C++0x では、安全な bool イディオムを使用しなければならない問題が修正されているため、C++0x では、basic_ios基本クラス テンプレートがoperator bool()明示的な変換演算子としてオーバーロードされます。この演算子は、現在の と同じセマンティクスを持っていoperator void*()ます。

于 2010-11-23T17:27:29.567 に答える
17

James の answerに加えて、これらのフラグは操作の結果を示すため、実行しない限り設定されないことを覚えておくことが重要です。

一般的なエラーは、これを行うことです:

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    std::ifstream file("main.cpp");

    while (!file.eof()) // while the file isn't at eof...
    {
        std::string line;
        std::getline(file, line); // ...read a line...

        std::cout << "> " << line << std::endl; // and print it
    }
}

ここでの問題は、最後の行eof()取得しようとするまで設定されないことです。その時点で、ストリームは「いいえ、もうありません!」と言うでしょう。設定します。つまり、「正しい」方法は次のとおりです。

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    std::ifstream file("main.cpp");

    for (;;)
    {
        std::string line;
        std::getline(file, line); // read a line...

        if (file.eof()) // ...and check if it we were at eof
            break;

        std::cout << "> " << line << std::endl;
    }
}

これにより、小切手が正しい場所に配置されます。ただし、これは非常に手に負えません。幸いなことに、 の戻り値はストリームであり、ストリームには、 を含むstd::getlineの値を持つブール コンテキストでテストできる変換演算子があります。したがって、次のように書くことができます。fail()eof()

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    std::ifstream file("main.cpp");

    std::string line;
    while (std::getline(file, line)) // get line, test if it was eof
        std::cout << "> " << line << std::endl;
}
于 2010-11-23T17:47:25.870 に答える