Почему iostream :: eof внутри условия цикла считается неправильным?


426 ов принято

Потому что вернется только после прочтения конца if ( scanf ( «...» , ...)! = EOF ) . Это не означает, что следующим чтением будет конец потока.while(!inStream.eof()){ int data; // yay, not end of stream yet, now read ... inStream >> data; // oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit) // do stuff with (now uninitialized) data }int data; while(inStream >> data){ // when we land here, we can be sure that the read was successful. // if it wasn't, the returned stream from operator>> would be converted to false // and the loop wouldn't even be entered // do stuff with correctly initialized data (hopefully) }

Рассмотрим это (и предположим, что следующее чтение будет в конце потока):

if(!(inStream >> data).eof())

Против этого:

if(!inStream.eof())
    inFile >> data

И на ваш второй вопрос: Потому что

eof

такой же как

fail()

и не то же самое,

while( !(in>>std::ws).eof() ) {  
   int data;
   in >> data;
   if ( in.fail() ) /* handle with break or throw */; 
   // now use data
}    

86

Нижняя строка: при правильной обработке белого пространства, как eofможно использовать (и даже более надежно, чем eof()для проверки ошибок):

eof()

( Спасибо Tony D за предложение выделить ответ. См. Его комментарий ниже, чтобы привести пример, почему это более надежное. )


Главный аргумент против использования, похоже, не содержит важной тонкости в отношении роли белого пространства. Мое предложение состоит в том, что проверка явно не только не всегда « всегда ошибочна », что, по-видимому, является преобладающим мнением в этой и подобных потоках SO, но при правильном обращении с белым пространством оно обеспечивает более чистую и надежную обработка ошибок и всегда правильное решение (хотя и не обязательно tersest).int data; while(in >> data) { /* ... */ } // which is equivalent to while( !(in >> data).fail() ) { /* ... */ }1 2 3 4 5<eof>

Подводя итог тому, что предлагается в качестве «правильного» завершения и порядка чтения, является следующее:

1 2 a 3 4 5<eof>

Неисправность из-за попытки чтения за пределами eof принимается за условие завершения. Это означает, что нет простого способа отличить успешный поток и тот, который действительно терпит неудачу по другим причинам, кроме 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)

Резюме. Правильно построенная while(stream >> n)не только возможна, но и ошибочна, но позволяет локализовать данные в пределах области действия и обеспечивает более четкое разделение проверки ошибок от бизнеса, как обычно. Это, как говорится, является, несомненно, более распространенным и кратким идиомом, и может быть предпочтительным в простых (единичных данных для типа чтения).while(!stream.eof()) { stream >> n; //some work on n; }


56 ов

Потому что, если программисты не пишут some work on n, они, возможно, напишут это:

some work on n

Здесь проблема заключается в том, что вы не можете обойтись eofbitбез предварительной проверки, было ли чтение потока успешным, потому что, если оно не увенчалось успехом, вы получите badbitнежелательный результат.

Все дело в том , что failbit, stream >> nили eofbitустанавливаются после того, как попытка чтения из потока. Так что если badbitсбой, то failbit, while (stream >> n)или streamнемедленно устанавливается, поэтому он более идиоматичен, если вы пишете false, потому что возвращаемый объект streamпреобразуется в, trueесли был некоторый сбой при чтении из потока, и, следовательно, цикл останавливается. И он преобразуется в, если чтение было успешным, и цикл продолжается.1 while (!read.fail()) { 2 cout << ch; 3 read.get(ch); 4 }


ch

Если вы используете линию 2 в 3 и строку 3 в 2, вы будете chпечататься дважды. Так что cout перед чтением.

C ++ iostream C ++ - вопросы и ответы,

c++,iostream,c++-faq,

472

Ответов: 4


426 ов принято

Потому что вернется только после прочтения конца if ( scanf ( «...» , ...)! = EOF ) . Это не означает, что следующим чтением будет конец потока.while(!inStream.eof()){ int data; // yay, not end of stream yet, now read ... inStream >> data; // oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit) // do stuff with (now uninitialized) data }int data; while(inStream >> data){ // when we land here, we can be sure that the read was successful. // if it wasn't, the returned stream from operator>> would be converted to false // and the loop wouldn't even be entered // do stuff with correctly initialized data (hopefully) }

Рассмотрим это (и предположим, что следующее чтение будет в конце потока):

if(!(inStream >> data).eof())

Против этого:

if(!inStream.eof())
    inFile >> data

И на ваш второй вопрос: Потому что

eof

такой же как

fail()

и не то же самое,

while( !(in>>std::ws).eof() ) {  
   int data;
   in >> data;
   if ( in.fail() ) /* handle with break or throw */; 
   // now use data
}    

86

Нижняя строка: при правильной обработке белого пространства, как eofможно использовать (и даже более надежно, чем eof()для проверки ошибок):

eof()

( Спасибо Tony D за предложение выделить ответ. См. Его комментарий ниже, чтобы привести пример, почему это более надежное. )


Главный аргумент против использования, похоже, не содержит важной тонкости в отношении роли белого пространства. Мое предложение состоит в том, что проверка явно не только не всегда « всегда ошибочна », что, по-видимому, является преобладающим мнением в этой и подобных потоках SO, но при правильном обращении с белым пространством оно обеспечивает более чистую и надежную обработка ошибок и всегда правильное решение (хотя и не обязательно tersest).int data; while(in >> data) { /* ... */ } // which is equivalent to while( !(in >> data).fail() ) { /* ... */ }1 2 3 4 5<eof>

Подводя итог тому, что предлагается в качестве «правильного» завершения и порядка чтения, является следующее:

1 2 a 3 4 5<eof>

Неисправность из-за попытки чтения за пределами eof принимается за условие завершения. Это означает, что нет простого способа отличить успешный поток и тот, который действительно терпит неудачу по другим причинам, кроме 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)

Резюме. Правильно построенная while(stream >> n)не только возможна, но и ошибочна, но позволяет локализовать данные в пределах области действия и обеспечивает более четкое разделение проверки ошибок от бизнеса, как обычно. Это, как говорится, является, несомненно, более распространенным и кратким идиомом, и может быть предпочтительным в простых (единичных данных для типа чтения).while(!stream.eof()) { stream >> n; //some work on n; }


56 ов

Потому что, если программисты не пишут some work on n, они, возможно, напишут это:

some work on n

Здесь проблема заключается в том, что вы не можете обойтись eofbitбез предварительной проверки, было ли чтение потока успешным, потому что, если оно не увенчалось успехом, вы получите badbitнежелательный результат.

Все дело в том , что failbit, stream >> nили eofbitустанавливаются после того, как попытка чтения из потока. Так что если badbitсбой, то failbit, while (stream >> n)или streamнемедленно устанавливается, поэтому он более идиоматичен, если вы пишете false, потому что возвращаемый объект streamпреобразуется в, trueесли был некоторый сбой при чтении из потока, и, следовательно, цикл останавливается. И он преобразуется в, если чтение было успешным, и цикл продолжается.1 while (!read.fail()) { 2 cout << ch; 3 read.get(ch); 4 }


ch

Если вы используете линию 2 в 3 и строку 3 в 2, вы будете chпечататься дважды. Так что cout перед чтением.

C ++ iostream C ++ - вопросы и ответы,
Похожие вопросы