为什么从流中提取字符串会设置eof位?

Jos*_*eld 10 c++ string iostream language-lawyer

假设我们有一个简单的流:

hello
Run Code Online (Sandbox Code Playgroud)

请注意,\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;
}
Run Code Online (Sandbox Code Playgroud)

但是,我不明白为什么会根据标准发生这种情况(我正在阅读C++ 11 - ISO/IEC 14882:2011(E)).operator>>(basic_stream<...>&, basic_string<...>&)被定义为表现得像格式化的输入函数.这意味着它构造了一个sentry对象,它继续吃掉空白字符.在这个例子中,没有,所以sentry构造完成没有问题.转换为a时bool,sentry对象给出true,因此提取器继续继续实际提取字符串.

然后将提取定义为:

提取并附加字符,直到出现以下任何一种情况:

  • n 字符存储;
  • 文件结束发生在输入序列上;
  • isspace(c,is.getloc())对于下一个可用的输入字符c,则为true .

在提取最后一个字符(如果有)之后,调用is.width(0)并销毁sentry对象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设置位的结果是,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]

ipc*_*ipc 9

std::stringstreambasic_istreamoperator>>std::string从中"提取物"的字符(如你发现了).

27.7.2.1类模板 basic_istream

2如果rdbuf() - > sbumpc()或rdbuf() - > sgetc()返回traits :: eof(),则输入函数除非另有明确说明,否则完成其操作并执行setstate(eofbit),在返回之前抛出ios_- base :: failure(27.5.5.4).

此外,"提取"意味着调用这两个函数.

3两组成员函数签名共享公共属性:格式化的输入函数(或提取器)和未格式化的输入函数.两组输入函数都被描述为通过调用rdbuf() - > sbumpc()或rdbuf() - > sgetc()来获取(或提取)输入字符.他们可能会使用istream的其他公共成员.

所以必须设置eof.