【发布时间】:2011-05-08 05:31:58
【问题描述】:
我已经使用<< 流运算符为对象实现了反序列化例程。该例程本身使用istreambuf_iterator<char> 从流中逐个提取字符,以构造对象。
最终,我的目标是能够使用istream_iterator<MyObject> 遍历流并将每个对象插入vector。相当标准,除了当istream_iterator 到达流尾时,我无法stop 进行迭代。现在,它只是永远循环,即使对 istream::tellg() 的调用表明我在文件的末尾。
重现问题的代码如下:
struct Foo
{
Foo() { }
Foo(char a_, char b_) : a(a_), b(b_) { }
char a;
char b;
};
// Output stream operator
std::ostream& operator << (std::ostream& os, const Foo& f)
{
os << f.a << f.b;
return os;
}
// Input stream operator
std::istream& operator >> (std::istream& is, Foo& f)
{
if (is.good())
{
std::istreambuf_iterator<char> it(is);
std::istreambuf_iterator<char> end;
if (it != end) {
f.a = *it++;
f.b = *it++;
}
}
return is;
}
int main()
{
{
std::ofstream ofs("foo.txt");
ofs << Foo('a', 'b') << Foo('c', 'd');
}
std::ifstream ifs("foo.txt");
std::istream_iterator<Foo> it(ifs);
std::istream_iterator<Foo> end;
for (; it != end; ++it) cout << *it << endl; // iterates infinitely
}
我知道在这个简单的示例中,我什至不需要 istreambuf_iterator,但我只是想简化问题,以便人们更有可能回答我的问题。
所以这里的问题是即使istreambuf_iterator 到达了流缓冲区的末尾,实际的流本身并没有进入EOF 状态。对istream::eof() 的调用返回false,即使istream::tellg() 返回文件中的最后一个字节,并且istreambuf_iterator<char>(ifs) 与istreambuf_iterator<char>() 比较为true,这意味着我肯定在流的末尾。
我查看了 IOstreams 库代码,以确切了解它如何确定 istream_iterator 是否位于结束位置,并且基本上它检查 istream::operator void*() const 的计算结果是否为 true。这个 istream 库函数简单地返回:
return this->fail() ? 0 : const_cast<basic_ios*>(this);
换句话说,如果设置了故障位,它将返回0 (false)。然后,它将这个值与istream_iterator 的默认构造实例中的相同值进行比较,以确定我们是否结束了。
所以当istreambuf_iterator 与结束迭代器比较为真时,我尝试在std::istream& operator >> (std::istream& is, Foo& f) 例程中手动设置故障位。这完美地工作,并正确终止了循环。但现在我真的很困惑。似乎istream_iterator 肯定 检查std::ios::failbit 以表示“流结束”条件。但这不是std::ios::eofbit 的用途吗?我认为failbit 是针对错误情况,例如无法打开fstream 的基础文件或其他情况。
那么,为什么我需要调用istream::setstate(std::ios::failbit) 来终止循环?
【问题讨论】:
-
永远循环表明流已经坏了。问题是为什么?
-
@Martin,好吧,即使我用
std::stringstream替换文件流,也会出现同样的问题。所以这不可能是某种低级文件相关的问题。 -
阅读@PigBen 的答案。原因是在外部级别,您在内部使用 istream_iterator(在 for_each 中)和 istreambuf_iterator(operatro >>)。您需要在使用中保持一致。在这两种情况下都使用 istreambuf_iterators,它应该可以工作。
标签: c++ iostream istream istream-iterator