Confused about using `std :: istreambuf_iterator`

I followed the deserialization procedure for the object using the stream operator <<. The procedure itself uses istreambuf_iterator<char>one by one to extract characters from the stream to build the object.

Ultimately, my goal is to be able to iterate through the stream with istream_iterator<MyObject>and insert each object into vector. Pretty standard, except that I can't get the istream_iteratoriteration to end when it hits the end of the stream. Right now, it just loops forever, although calls istream::tellg()indicate that I'm at the end of the file.

Here is the code to reproduce the problem:

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);

, 0 (false), . istream_iterator, , .

, failbit std::istream& operator >> (std::istream& is, Foo& f), istreambuf_iterator true . . . , istream_iterator std::ios::failbit, " ". std::ios::eofbit? , failbit , , fstream - .

, istream::setstate(std::ios::failbit), ?

+3
5

istreambuf_iterator, streambuf istream. streambuf ( istream), streambuf istream. istream , eof.

- :

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

Edit

, , . 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. , ! true , , eofbit .

, , , istream NULL'd. , , istream, NULL .

+6

, , istream_iterator , , istream ios_base. istream , istream, streambuf.

> , istreambuf_iterator streambuf — , basic_streambuf::sgetc() ( operator*) basic_streambuf::sbumpc() ( operator++). , , basic_streambuf::gptr.

, , , std::basic_istream& operator>>(std::basic_istream&, T&). , basic_ios::setstate(badbit) , , basic_ios::setstate(eofbit). extracter , Foo.

, istreambuf_iterator , istream. istream, , , .

+3

operator>> failbit , Foo. , eofbit , . :

// 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;

        std::ios_base::iostate err = it == end ? (std::ios_base::eofbit |
                                                  std::ios_base::failbit) :
                                                 std::ios_base::goodbit;
        if (err == std::ios_base::goodbit) {
            char a = *it;
            if (++it != end)
            {
                char b = *it;
                if (++it == end)
                    err = std::ios_base::eofbit;
                f.a = a;
                f.b = b;
            }
            else
                err = std::ios_base::eofbit | std::ios_base::failbit;
        }
        if (err)
            is.setstate(err);
    }
    else
        is.setstate(std::ios_base::failbit);
    return is;
}

, failbit eofbit eof , , . , if (is.good()) , failbit. !good(), eofbit.

, istream::sentry . sentry , failbit:

// Input stream operator
std::istream& operator >> (std::istream& is, Foo& f)
{
    std::istream::sentry ok(is);
    if (ok) 
    {
        std::istreambuf_iterator<char> it(is);
        std::istreambuf_iterator<char> end;

        std::ios_base::iostate err = it == end ? (std::ios_base::eofbit |
                                                  std::ios_base::failbit) :
                                                 std::ios_base::goodbit;
        if (err == std::ios_base::goodbit) {
            char a = *it;
            if (++it != end)
            {
                char b = *it;
                if (++it == end)
                    err = std::ios_base::eofbit;
                f.a = a;
                f.b = b;
            }
            else
                err = std::ios_base::eofbit | std::ios_base::failbit;
        }
        if (err)
            is.setstate(err);
    }
    return is;
}

sentry . , . , , :

    std::istream::sentry ok(is, true);

sentry , failbit, eofbit.

+2

, :

:

// Input stream operator
std::istream& operator >> (std::istream& is, Foo& f)
{
    f.a = is.get();
    f.b = is.get();

    return is;
}
+1

, .equal() .

for (; !it.equal(end); ++it) cout << *it << endl;

, while for:

while ( !it.equal(end)) {
    cout << *it++ << endl;
}

, , ( ) while .

. , , , eof. , , .equal().

0

Source: https://habr.com/ru/post/1774210/


All Articles