結論: 空白を適切に処理すると、次のようeof
に使用できます(fail()
エラーチェックよりも信頼性が高くなります)。
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
(答えを強調する提案をしてくれたTony Dに感謝します。これがより堅牢である理由の例については、以下の彼のコメントを参照してください。)
使用に反対する主な議論eof()
は、空白の役割について重要な微妙さが欠けているようです。私の命題は、eof()
明示的にチェックすることは「常に間違っている」だけでなく、これと同様のSOスレッドで最も重要な意見であるように見えるだけでなく、空白を適切に処理することで、よりクリーンで信頼性が高くなることです。エラー処理であり、常に正しい解決策です(ただし、必ずしも最も簡潔ではありません)。
「適切な」終了と読み取り順序として提案されているものを要約すると、次のようになります。
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
eofを超えた読み取り試行による障害は、終了条件と見なされます。つまり、成功したストリームとeof以外の理由で本当に失敗したストリームを簡単に区別する方法はありません。次のストリームを取得します。
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
3つの入力すべてのセットfailbit
で終了します。最初と3番目にも設定されます。したがって、ループを過ぎると、適切な入力(1番目)と不適切な入力(2番目と3番目)を区別するために、非常に醜い追加のロジックが必要になります。eofbit
一方、次の点を考慮してください。
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
ここでin.fail()
は、読むものがある限り、それが正しいものであることを確認します。その目的は単なるwhile-loopターミネーターではありません。
これまでのところ良いですが、ストリームに末尾のスペースがある場合はどうなりeof()
ますか?ターミネーターとしての主な懸念のように聞こえますか?
エラー処理を引き渡す必要はありません。空白を食べ尽くすだけです:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
設定中に、ストリーム内の空間を末尾任意の潜在的な(ゼロ以上)スキップeofbit
、およびではありませんfailbit
。したがって、in.fail()
読み取るデータが少なくとも1つあれば、期待どおりに機能します。すべて空白のストリームも許容できる場合、正しい形式は次のとおりです。
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
概要:適切に構築することwhile(!eof)
は、可能で間違いではないだけでなく、データをスコープ内にローカライズすることができ、通常どおりエラーチェックをビジネスから明確に分離することができます。そうは言っても、while(!fail)
間違いなくより一般的で簡潔なイディオムであり、単純な(読み取りタイプごとに単一のデータ)シナリオで好まれます。
scanf(...) != EOF
Cでも機能しませんscanf
。正常に解析および割り当てられたフィールドの数を返すためです。正しい条件は、scanf(...) < n
ここでn
フォーマット文字列内のフィールドの数です。