Скажем, у нас есть поток, содержащий просто:
hello
Обратите внимание, что в конце нет лишнего \n, как это часто бывает в текстовом файле. Теперь следующий простой код показывает, что бит eof устанавливается в потоке после извлечения одного std::string.
int main(int argc, const char* argv[])
{
std::stringstream ss("hello");
std::string result;
ss >> result;
std::cout << ss.eof() << std::endl; // Outputs 1
return 0;
}
Однако я не понимаю, почему это произойдет в соответствии со стандартом (я читаю С++ 11 - ISO/IEC 14882: 2011 (E)). operator>>(basic_stream<...>&, basic_string<...>&) определяется как поведение как форматированная входная функция. Это означает, что он создает объект sentry, который переходит к пропуску пробельных символов. В этом примере их нет, поэтому конструкция sentry завершается без проблем. При преобразовании в bool объект sentry дает true, поэтому экстрактор продолжает работать с фактическим извлечением строки.
Затем извлечение определяется как:
Символы извлекаются и добавляются до тех пор, пока не произойдет следующее:
nсохраняются символы- конец файла происходит во входной последовательности;
isspace(c,is.getloc())верен для следующего доступного входного символа c.После того, как последний символ (если он есть) извлечен, вызывается is.width(0), и сторожевой объект k уничтожается. Если функция не извлекает никаких символов, она вызывает
is.setstate(ios::failbit), которая может бросатьios_base::failure(27.5.5.4).
Ничто здесь не приводит к установке бит eof. Да, извлечение останавливается, если оно попадает в конец файла, но оно не устанавливает бит. Фактически бит eof должен быть установлен только в том случае, если мы делаем еще один ss >> result;, потому что, когда sentry пытается сохнуть пробелы, произойдет следующая ситуация:
Если
is.rdbuf()->sbumpc()илиis.rdbuf()->sgetc()возвращаетtraits::eof(), функция вызываетsetstate(failbit | eofbit)
Однако это пока еще не происходит, поскольку failbit не устанавливается.
Следствие установленного бита eof заключается в том, что единственная причина, по которой evil-idiom while (!stream.eof()) не работает при чтении файлов из-за дополнительного \n в конце, а не потому, что eof бит еще не установлен. Мой компилятор с радостью устанавливает бит eof, когда извлечения останавливается в конце файла.
Так должно ли это происходить? Или стандартный означает сказать, что setstate(eofbit) должен произойти?
Чтобы сделать это проще, соответствующие разделы стандарта:
- 21.4.8.9 Вставки и экстракторы [string.io]
- 27.7.2.2 Форматированные входные функции [istream.formatted]
- 27.7.2.1.3 Класс
basic_istream::sentry[istream:: sentry]