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