c – 对`std :: istreambuf_iterator`的使用感到困惑

c – 对`std :: istreambuf_iterator`的使用感到困惑,第1张

概述我使用<<<<<<<<<<<<<流 *** 作符.例程本身使用istreambuf_iterator< char>从流中逐个提取字符,以构造对象. 最终,我的目标是能够使用istream_iterator< MyObject>遍历流.并将每个对象插入向量中.非常标准,除了我遇到istream_iterator在它到达流末尾时停止迭代时遇到了麻烦.现在,它只是永远循环,即使调用istream :: tell 我使用<<<<<<<<<<<<<流 *** 作符.例程本身使用istreambuf_iterator< char>从流中逐个提取字符,以构造对象.

最终,我的目标是能够使用istream_iterator< MyObject>遍历流.并将每个对象插入向量中.非常标准,除了我遇到istream_iterator在它到达流末尾时停止迭代时遇到了麻烦.现在,它只是永远循环,即使调用istream :: tellg()表明我在文件的末尾.

这是重现问题的代码:

struct Foo{    Foo() { }        Foo(char a_,char b_) : a(a_),b(b_) { }    char a;    char b;};// Output stream operatorstd::ostream& operator << (std::ostream& os,const Foo& f){    os << f.a << f.b;    return os;}// input stream operatorstd::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)将true与istreambuf_iterator< char>()进行比较,这意味着我肯定是在流的最后.

我查看了IOstreams库代码,以确切了解它是如何确定istream_iterator是否位于结束位置,并且基本上它检查istream :: operator voID *()const是否计算为true.这个istream库函数只返回:

return this->fail() ? 0 : const_cast<basic_ios*>(this);

换句话说,如果设置了failbit,则返回0(false).然后,它将此值与istream_iterator的默认构造实例中的相同值进行比较,以确定我们是否在最后.

所以我尝试在我的std :: istream&中手动设置failbit.运算符>> (std :: istream& is,Foo& f)例程,当istreambuf_iterator将true与结束迭代器进行比较时.这非常有效,并且正确地终止了循环.但现在我真的很困惑.似乎istream_iterator肯定会检查std :: ios :: failbit以表示“流结束”条件.但这不是std :: ios :: eofbit的用途吗?我认为failbit是针对错误条件的,例如,如果无法打开fstream的基础文件或其他内容.

那么,为什么我需要调用istream :: setstate(std :: ios :: failbit)来使循环终止?

解决方法 使用istreambuf_iterator时,您正在 *** 作istream对象的基础streambuf对象. streambuf对象对它的所有者(istream对象)一无所知,因此在streambuf对象上调用函数不会对istream对象进行更改.这就是当你到达eof时没有设置istream对象中的标志的原因.

做这样的事情:

std::istream& operator >> (std::istream& is,Foo& f){    is.read(&f.a,sizeof(f.a));    is.read(&f.b,sizeof(f.b));    return is;}

编辑

我在调试器中单步执行代码,这就是我找到的. istream_iterator有两个内部数据成员.指向关联的istream对象的指针,以及模板类型的对象(在本例中为Foo).当你调用它时,它会调用这个函数:

voID _Getval(){    // get a _Ty value if possible    if (_Myistr != 0 && !(*_Myistr >> _Myval))        _Myistr = 0;}

_Myistr是istream指针,_Myval是Foo对象.如果你看这里:

!(*_Myistr >> _Myval)

这就是它所谓的 *** 作符>>超载.它叫运算符!在返回的istream对象上.正如你可以看到here,运算符!如果设置了failbit或badbit,则只返回true,eofbit不会这样做.

那么,接下来会发生什么,如果设置了failbit或badbit,则istream指针变为NulL.下次将迭代器与结束迭代器进行比较时,它会比较istream指针,它们都是NulL.

总结

以上是内存溢出为你收集整理的c – 对`std :: istreambuf_iterator`的使用感到困惑全部内容,希望文章能够帮你解决c – 对`std :: istreambuf_iterator`的使用感到困惑所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1219109.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存