Скажем, у нас есть поток, содержащий просто:
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]