В нижней строке: При правильной обработке пробелов, вот как можно использовать eof
(и даже быть более надежным, чем fail()
для проверки ошибок):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Спасибо Тони Д. за предложение выделить ответ. См. Его комментарий ниже для примера того, почему это более надежно. )
Theосновной аргумент против использования 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)
оканчивается наустановите failbit
для все три входа.В первом и третьем также установлен eofbit
.Таким образом, после цикла требуется очень уродливая дополнительная логика, чтобы отличить правильный ввод (1-й) от неправильного (2-й и 3-й).
Принимая во внимание следующее:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Здесь,in.fail()
проверяет, что если есть что почитать, то оно правильное.Это не просто терминатор цикла while.
Пока все хорошо, но что произойдет, если в потоке есть конечный пробел - что звучит как основная проблема против 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()
работает как положено, если есть хотя бы одна информация для чтения.Если все пустые потоки также приемлемы, то правильная форма будет:
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)
, несомненно, является более распространенной и краткой идиомой и может быть предпочтительным в простых (один тип данных на чтение) сценариях.