Знизу вгорі: При правильній обробці пробілів, наступне - як 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()
підтверджується, що поки є що читати, це правильне. Його мета - не простий термінатор, а цикл.
Поки що добре, але що станеться, якщо в потоці є простір - що звучить як головне занепокоєння 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
кількість полів у рядку формату.