Почему если флаг состояния потока eof поднят, то флаг good опущен?

В стандартных потоках флаг конца файла поднимается не тогда, когда указатель чтения просто тихонько "достиг конца файла", а тогда, когда вызывающий код предпримет попытку

продвинуть его дальше

, за конец файла. То есть флаг конца файла будет поднят тогда, когда конец файла фактически уже достигнут, а внешний код (который об этом еще не знает) тем не менее попытается выполнить попытку чтения данных из файла. Эта попытка будет, разумеется, неудачной. И вот только в этот момент в потоке будет поднят флаг 'eof'.

Таким образом, поднятие флага 'eof' - это всегда результат

ошибочной

ситуации - попытки чтения несуществующих данных за концом файла. Именно по этой причине ситуация 'eof' не считается 'good'.

Вот в таком коде, где входной поток состоит из одного единственного символа, флаг 'eof' после прочтения этого символа выставлен

не будет

. А появится он только после попытки прочтения второго, несуществующего символа.

C++Выделить код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

string str= "s";
istringstream is(str);
 
char c;
 
is >> c;
if (is.eof())
  printf ("+eofn");
else
  printf ("-eofn");
 
is >> c;
if (is.eof())
  printf ("+eofn");
else
  printf ("-eofn");

Когда выполняется чтение из потока разнообразных многосимвольных объектов (строк, чисел и т.п.), то будет выставлен флаг 'eof' или не будет зависит от того, по какой причине было прервано чтение символов из потока. Если оно было прервано из-за попытки чтения после конца файла, то в вызывающем коде вы увидите 'eof'. Если же чтение было прервано по какой-то другой причине, что в вызывающем коде вы не увидите 'eof', даже если фактически коней файла уже достигнут.

Например, в вашем примере вы читаете из потока строку неограниченной длины. Алгоритм чтения строки будет выдергивать из входного потока один символ за другим, пока не встретит пробел или конец файла. "Встретит конец файла" в данном случае означает именно "попытается прочитать несуществующий символ". Именно это и происходит в вашем примере. Оператор 'is >> str' успешно читает шесть символов (флага 'eof' после этого еще не возникает), а затем пытается прочитать седьмой. Это ему не удается и выставляется флаг 'eof'. Именно этот флаг вы и видите в вызывающем коде.

Однако если вы будете читать вашу строку вот так

C++Выделить код

1
2
3

string str= "stroka";
istringstream is (str);
is >> setw(6) >> str;

то обнаружите, что никакого флага 'eof' при таком чтении не выставляется. Чтение было прекращено по причине достижения заданной длины. Попытки чтения седьмого символа не было и, соответственно, ситуация 'eof' обнаружена не была.