加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 10:17:55 所属栏目:百科 来源:网络整理
导读:我使用流操作符.例程本身使用istreambuf_iterator char从流中逐个提取字符,以构造对象. 最终,我的目标是能够使用istream_iterator MyObject遍历流.并将每个对象插入向量中.非常标准,除了我遇到istream_iterator在它到达流末尾时停止迭代时遇到了麻烦.现在,它
我使用<<<<<<<<<<<<<流操作符.例程本身使用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 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)将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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读