Най-долу в горния ред: При правилно боравене с бяло пространство, следното е как eof
може да се използва (и дори да бъде по-надежден от fail()
за проверка на грешки):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
(Благодаря на Tony D за предложението да подчертаем отговора. Вижте неговия коментар по-долу за пример защо това е по-стабилно.)
Основният аргумент срещу използването на 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)
безспорно е по-разпространен и кратък идиом и може да бъде предпочитан в прости (едни данни за тип четене) сценарии.
person
sly
schedule
23.11.2012
scanf(...) != EOF
също няма да работи в C, защотоscanf
връща броя на успешно анализираните и присвоени полета. Правилното условие еscanf(...) < n
, къдетоn
е броят на полетата във форматния низ. - person Ben Voigt   schedule 05.04.2012EOF
, ако бъде открит край на файла преди първото преобразуване на поле (успешно или не). Ако между полетата се достигне край на файла, ще се върне броя на полетата, които са успешно конвертирани и съхранени. Което прави сравнението сEOF
грешно. - person Ben Voigt   schedule 24.11.2012.eof()
след излизане от цикъла. - person Ben Voigt   schedule 24.11.2012while(fail)
цикълът завършва както с действителен отказ, така и с eof. Помислете дали имате нужда от 3 int на итерация (да речем, че четете x-y-z точка или нещо подобно), но погрешно има само две int в потока. - person sly   schedule 24.11.2012while(!feof(file))
винаги е грешен ?. Тъй като флагът се задава само след натискане на EOF. - person legends2k   schedule 21.03.2014while (in >> x) { if (in >> y >> z) use(x, y, z); else FATAL("got an int not followed by 2 more!"); } if (!eof()) FATAL("didn't get integer where expected");
? Ако не, за какво поточно съдържание това не ще работи добре? - person Tony Delroy   schedule 07.11.2014