Итог: при правильной обработке пробелов, вот как 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это число полей в строке формата.