以前の質問に触発されて
新しい C++ プログラマーにとってよくある間違いは、次の行に沿ったものをファイルから読み取ることです。
std::ifstream file("foo.txt");
std::string line;
while (!file.eof()) {
file >> line;
// Do something with line
}
多くの場合、ファイルの最後の行が 2 回読み取られたと報告されます。この問題の一般的な説明 (以前に説明したもの) は次のようになります。
抽出がファイルの終わりで停止した場合ではなく、ファイルの終わりを抽出しようとした場合にのみ、ストリームに EOF ビットが設定されます。
file.eof()
前の読み取りがファイルの終わりに到達したかどうかのみを通知し、次の読み取りが終了したかどうかは通知しません。最後の行が抽出された後、EOF ビットはまだ設定されておらず、反復がもう一度行われます。ただし、この最後の繰り返しでは、抽出は失敗し、line
以前と同じ内容のままです。つまり、最後の行が重複しています。
ただし、この説明の最初の文が間違っているため、コードが何を行っているかの説明も間違っています。
フォーマットされた入力関数の定義 (である) は、入力文字を使用する、または入力文字を取得するためoperator>>(std::string&)
の抽出を定義します。これらの関数のいずれかが を返す場合、EOF ビットが設定されると述べています。rdbuf()->sbumpc()
rdbuf()->sgetc()
traits::eof()
rdbuf()->sbumpc()
またはが をrdbuf()->sgetc()
返す場合traits::eof()
、入力関数は、特に明記されていない限り、そのアクションを完了し、戻る前に (27.5.5.4)setstate(eofbit)
をスローする可能性がある を実行します。ios_base::failure
std::stringstream
これは、ファイルではなくを使用する単純な例で確認できます (どちらも入力ストリームであり、抽出時に同じように動作します)。
int main(int argc, const char* argv[])
{
std::stringstream ss("hello");
std::string result;
ss >> result;
std::cout << ss.eof() << std::endl; // Outputs 1
return 0;
}
ここで、単一の抽出がhello
文字列から取得し、EOF ビットを 1 に設定することは明らかです。
では、説明の何が問題なのですか?!file.eof()
最終行が重複する原因となるファイルの違いは何ですか? !file.eof()
抽出条件として使用してはいけない本当の理由は何ですか?