[英]Why does string extraction from a stream set the eof bit?
假设我们有一个简单的流:
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>>(basic_stream<...>&, basic_string<...>&)
被定义为行为类似于格式化的输入函数 。 这意味着它构造了一个sentry
对象,它继续吃掉空白字符。 在这个例子中,没有,所以sentry
结构完成没有问题。 当转换为bool
, sentry
对象给出true
,因此提取器继续继续实际提取字符串。
然后将提取定义为:
提取并附加字符,直到出现以下任何一种情况:
- 存储
n
字符;- 文件结束发生在输入序列上;
- 对于下一个可用的输入字符c
isspace(c,is.getloc())
为true。在提取最后一个字符(如果有)之后,调用is.width(0)并销毁sentry对象k。 如果函数没有提取任何字符,则调用
is.setstate(ios::failbit)
,这可能会抛出ios_base::failure
(27.5.5.4)。
这里没有任何东西实际上导致eof
位被设置。 是的,如果提取到达文件结尾,则提取停止,但它不会设置该位。 事实上,只有当我们做另一个ss >> result;
才应该设置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)
?
为方便起见,标准的相关部分是:
basic_istream::sentry
[istream :: sentry] std::stringstream
是一个basic_istream
, std::string
的operator>>
从中提取“字符”(如你basic_istream
)。
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。
直观地说,设置EOF位是因为在读取操作期间提取字符串时,流确实命中了文件的末尾。 具体来说,它连续从输入流中读取字符,因为它在遇到空白字符之前到达流的末尾而停止。 因此,流设置EOF位以标记到达流的末尾。 请注意,这是不一样的报告失效-在操作成功完成-但EOF位点是不报告故障。 这是为了标记遇到流的末尾。
我没有特定的规范来支持这一点,但是当我有机会的时候我会尝试寻找一个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.