【问题标题】:Why does string extraction from a stream set the eof bit?为什么从流中提取字符串会设置 eof 位?
【发布时间】:2013-01-13 12:19:03
【问题描述】:

假设我们有一个只包含以下内容的流:

hello

请注意,末尾没有额外的\n,就像文本文件中经常出现的那样。现在,下面的简单代码显示在提取单个 std::string 后在流上设置了 eof 位。

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&gt;&gt;(basic_stream&lt;...&gt;&amp;, basic_string&lt;...&gt;&amp;) 被定义为表现得像一个格式化的输入函数。这意味着它构造了一个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 &gt;&gt; result; 时才应该设置,因为当sentry 试图吞噬空白时,会出现以下情况:

如果is.rdbuf()-&gt;sbumpc()is.rdbuf()-&gt;sgetc() 返回traits::eof(),则函数调用setstate(failbit | eofbit)

但是,这肯定还没有发生,因为 failbit 尚未设置。

设置eof 位的结果是,邪恶习语while (!stream.eof()) 在读取文件时不起作用的唯一原因是因为末尾有额外的\n不是 em> 因为尚未设置 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]

【问题讨论】:

  • 邪恶的成语是邪恶的,因为它也无法解释输入流甚至不存在的情况,例如当您打开一个没有打开 stdin 的程序时。
  • +1 格式良好的问题,包括对标准和最小示例的引用。

标签: c++ string iostream language-lawyer


【解决方案1】:

std::stringstreambasic_istreamoperator&gt;&gt; 中的 std::string“提取”字符(如您所见)。

27.7.2.1 类模板basic_istream

2 如果 rdbuf()->sbumpc() 或 rdbuf()->sgetc() 返回 traits::eof(),则输入函数,除了 as 另有明确说明,完成其动作并执行 setstate(eofbit),这可能会抛出 ios_- base::failure (27.5.5.4),在返回之前。

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

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

所以必须设置eof。

【讨论】:

  • 啊,你明白了!我没有看到关于提取定义的那一段。实际上,如果提取到达文件末尾,eof 位将被设置。谢谢!
【解决方案2】:

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

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

【讨论】:

  • 谢谢。这是一个很好的直观描述。 @ipc 设法找到了实现它的标准报价。
猜你喜欢
  • 2023-03-10
  • 2017-03-11
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多