【发布时间】: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>>(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 位的结果是,邪恶习语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