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

时间:2013-01-29 20:01:38

标签: c++ string iostream language-lawyer

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

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;
}

但是,我不明白为什么会根据标准发生这种情况(我正在阅读C ++ 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)并销毁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而且 not 因为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]

2 个答案:

答案 0 :(得分:9)

std::stringstreambasic_istreamoperator>> std::string从中提取“字符”(正如您所发现的那样)。

27.7.2.1班级模板basic_istream

  

2如果rdbuf() - &gt; sbumpc()或rdbuf() - &gt; sgetc()返回traits :: eof(),那么输入函数除外   明确地另外说明,完成它的行动并且做setstate(eofbit),可能抛出ios_-   base :: failure(27.5.5.4),返回之前。

另外,“提取”意味着调用这两个函数。

  

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

因此必须设置eof。

答案 1 :(得分:3)

直观地说,设置EOF位是因为在读取操作期间提取字符串时,流确实命中了文件的末尾。具体来说,它连续从输入流中读取字符,因为它在遇到空白字符之前到达流的末尾而停止。因此,流设置EOF位以标记到达流的末尾。请注意, 与报告失败相同 - 操作已成功完成 - 但EOF位的点不是报告失败。这是为了表明遇到了流的末尾。

我没有特定的规范来支持这一点,但是当我有机会的时候我会尝试寻找一个。