Copying with istream_iterator

Discussion in 'C++' started by Alex Vinokur, Jul 21, 2004.

  1. Alex Vinokur

    Alex Vinokur Guest

    ------ foo.cpp : BEGIN ------
    #include <cassert>
    #include <vector>
    #include <string>
    #include <iostream>
    #include <iterator>
    #include <fstream>
    using namespace std;


    int main ()
    {
    ifstream f("foo.in", ios_base::binary);
    assert (f);
    istream_iterator<string> b(f), e;

    cout << "(1) File : ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;

    cout << "(2) File : ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;

    return 0;
    }
    ------ foo.cpp : END --------


    ------ Compilation & Run : BEGIN ------

    $ g++ --version
    g++ (GCC) 3.3.1 (cygming special)
    [---omitted---]


    $ g++ -mno-cygwin foo.cpp

    $ a
    (1) File : abc xyz ijk pqr
    (2) File : abc

    ------ Compilation & Run : END --------

    Why do two copy()'s produce different output?


    --
    Alex Vinokur
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Jul 21, 2004
    #1
    1. Advertising

  2. Alex Vinokur wrote:
    > ------ foo.cpp : BEGIN ------
    > #include <cassert>
    > #include <vector>
    > #include <string>
    > #include <iostream>
    > #include <iterator>
    > #include <fstream>
    > using namespace std;
    >
    >
    > int main ()
    > {
    > ifstream f("foo.in", ios_base::binary);
    > assert (f);
    > istream_iterator<string> b(f), e;
    >
    > cout << "(1) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > cout << "(2) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > return 0;
    > }
    > ------ foo.cpp : END --------
    >
    >
    > ------ Compilation & Run : BEGIN ------
    >
    > $ g++ --version
    > g++ (GCC) 3.3.1 (cygming special)
    > [---omitted---]
    >
    >
    > $ g++ -mno-cygwin foo.cpp
    >
    > $ a
    > (1) File : abc xyz ijk pqr
    > (2) File : abc
    >
    > ------ Compilation & Run : END --------
    >
    > Why do two copy()'s produce different output?


    Probably because you didn't rewind the stream. The 'istream_iterator'
    holds a reference to the stream it's initialised with. Any attempt to
    read past the end of the file produce undefined behaviour.

    Victor
    Victor Bazarov, Jul 21, 2004
    #2
    1. Advertising

  3. Alex Vinokur

    Alex Vinokur Guest

    "Victor Bazarov" <> wrote in message news:rzxLc.30$09.us.to.verio.net...
    > Alex Vinokur wrote:

    [snip]
    > > Why do two copy()'s produce different output?

    >
    > Probably because you didn't rewind the stream. The 'istream_iterator'
    > holds a reference to the stream it's initialised with. Any attempt to
    > read past the end of the file produce undefined behaviour.

    [snip]


    Something like:

    ------ foo1.cpp : BEGIN ------
    #include <cassert>
    #include <string>
    #include <iostream>
    #include <iterator>
    #include <fstream>
    using namespace std;

    int main ()
    {
    ifstream f("foo.in");
    assert (f);
    istream_iterator<string> b(f), e;

    cout << distance (b, e) << endl;
    f.seekg (0, ios::beg);
    cout << distance (b, e) << endl;

    return 0;
    }
    ------ foo1.cpp : END --------

    ------ Run : BEGIN ------

    $ a
    4
    1

    ------ Run : END --------

    What happened to 'b' after first 'distance'?
    Where should one put 'seekg' (rewind) to get the same result after second 'distance'?


    --
    Alex Vinokur
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Jul 21, 2004
    #3
  4. Alex Vinokur wrote:
    > "Victor Bazarov" <> wrote in message news:rzxLc.30$09.us.to.verio.net...
    >
    >>Alex Vinokur wrote:

    >
    > [snip]
    >
    >>>Why do two copy()'s produce different output?

    >>
    >>Probably because you didn't rewind the stream. The 'istream_iterator'
    >>holds a reference to the stream it's initialised with. Any attempt to
    >>read past the end of the file produce undefined behaviour.

    >
    > [snip]
    >
    >
    > Something like:
    >
    > ------ foo1.cpp : BEGIN ------
    > #include <cassert>
    > #include <string>
    > #include <iostream>
    > #include <iterator>
    > #include <fstream>
    > using namespace std;
    >
    > int main ()
    > {
    > ifstream f("foo.in");
    > assert (f);
    > istream_iterator<string> b(f), e;
    >
    > cout << distance (b, e) << endl;
    > f.seekg (0, ios::beg);
    > cout << distance (b, e) << endl;
    >
    > return 0;
    > }
    > ------ foo1.cpp : END --------
    >
    > ------ Run : BEGIN ------
    >
    > $ a
    > 4
    > 1
    >
    > ------ Run : END --------
    >
    > What happened to 'b' after first 'distance'?


    'distance' uses operator++ to count the number of increments. That
    changes the original iterator, doesn't it?

    > Where should one put 'seekg' (rewind) to get the same result after second 'distance'?


    Nowhere. Don't use 'distance'. Perhaps it's a bug in your library
    implementation. Did you check how 'distance' worked? The trouble
    with 'istream_iterator' is that the connection between it and the
    stream is mutating even after you make a copy of the iterator. You
    might get lucky that your stream can be brought back to the same
    state somehow, or you might never get lucky, and the stream, once it
    has been read, can never go back to its beginning...

    Why do you need to do that, anyway?

    Victor
    Victor Bazarov, Jul 21, 2004
    #4
  5. Alex Vinokur

    Alex Vinokur Guest

    "Victor Bazarov" <> wrote in message news:uxzLc.34$09.us.to.verio.net...
    > Alex Vinokur wrote:
    > > "Victor Bazarov" <> wrote in message news:rzxLc.30$09.us.to.verio.net...
    > >
    > >>Alex Vinokur wrote:

    > >
    > > [snip]
    > >
    > >>>Why do two copy()'s produce different output?
    > >>
    > >>Probably because you didn't rewind the stream. The 'istream_iterator'
    > >>holds a reference to the stream it's initialised with. Any attempt to
    > >>read past the end of the file produce undefined behaviour.

    > >
    > > [snip]
    > >
    > >
    > > Something like:
    > >
    > > ------ foo1.cpp : BEGIN ------
    > > #include <cassert>
    > > #include <string>
    > > #include <iostream>
    > > #include <iterator>
    > > #include <fstream>
    > > using namespace std;
    > >
    > > int main ()
    > > {
    > > ifstream f("foo.in");
    > > assert (f);
    > > istream_iterator<string> b(f), e;
    > >
    > > cout << distance (b, e) << endl;
    > > f.seekg (0, ios::beg);
    > > cout << distance (b, e) << endl;
    > >
    > > return 0;
    > > }
    > > ------ foo1.cpp : END --------
    > >
    > > ------ Run : BEGIN ------
    > >
    > > $ a
    > > 4
    > > 1
    > >
    > > ------ Run : END --------
    > >
    > > What happened to 'b' after first 'distance'?

    >
    > 'distance' uses operator++ to count the number of increments. That
    > changes the original iterator, doesn't it?
    >
    > > Where should one put 'seekg' (rewind) to get the same result after second 'distance'?

    >
    > Nowhere. Don't use 'distance'. Perhaps it's a bug in your library
    > implementation.


    Microsoft C++ Version 13.00.9466 for 80x86,
    Borland C++ 5.5.1,
    Digital Mars C++ 8.38n
    produce the same behavior.

    > Did you check how 'distance' worked? The trouble
    > with 'istream_iterator' is that the connection between it and the
    > stream is mutating even after you make a copy of the iterator. You
    > might get lucky that your stream can be brought back to the same
    > state somehow, or you might never get lucky, and the stream, once it
    > has been read, can never go back to its beginning...
    >
    > Why do you need to do that, anyway?

    [snip]

    I didn't need that, but I came across strange (to me) behavior of copy() while preparing my reply to thread
    http://groups-beta.google.com/group/comp.lang.c /browse_thread/thread/43ed64bb7a94fa3a/

    Now I would like to understand this situation.


    --
    Alex Vinokur
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Jul 21, 2004
    #5
  6. Alex Vinokur wrote:
    > "Victor Bazarov" <> wrote in message news:uxzLc.34$09.us.to.verio.net...
    >
    >>Alex Vinokur wrote:
    >>
    >>>"Victor Bazarov" <> wrote in message news:rzxLc.30$09.us.to.verio.net...
    >>>
    >>>
    >>>>Alex Vinokur wrote:
    >>>
    >>>[snip]
    >>>
    >>>
    >>>>>Why do two copy()'s produce different output?
    >>>>
    >>>>Probably because you didn't rewind the stream. The 'istream_iterator'
    >>>>holds a reference to the stream it's initialised with. Any attempt to
    >>>>read past the end of the file produce undefined behaviour.
    >>>
    >>>[snip]
    >>>
    >>>
    >>>Something like:
    >>>
    >>>------ foo1.cpp : BEGIN ------
    >>>#include <cassert>
    >>>#include <string>
    >>>#include <iostream>
    >>>#include <iterator>
    >>>#include <fstream>
    >>>using namespace std;
    >>>
    >>>int main ()
    >>>{
    >>>ifstream f("foo.in");
    >>> assert (f);
    >>>istream_iterator<string> b(f), e;
    >>>
    >>> cout << distance (b, e) << endl;
    >>> f.seekg (0, ios::beg);
    >>> cout << distance (b, e) << endl;
    >>>
    >>> return 0;
    >>>}
    >>>------ foo1.cpp : END --------
    >>>
    >>>------ Run : BEGIN ------
    >>>
    >>>$ a
    >>>4
    >>>1
    >>>
    >>>------ Run : END --------
    >>>
    >>>What happened to 'b' after first 'distance'?

    >>
    >>'distance' uses operator++ to count the number of increments. That
    >>changes the original iterator, doesn't it?
    >>
    >>
    >>>Where should one put 'seekg' (rewind) to get the same result after second 'distance'?

    >>
    >>Nowhere. Don't use 'distance'. Perhaps it's a bug in your library
    >>implementation.

    >
    >
    > Microsoft C++ Version 13.00.9466 for 80x86,
    > Borland C++ 5.5.1,
    > Digital Mars C++ 8.38n
    > produce the same behavior.
    >
    >
    >> Did you check how 'distance' worked? The trouble
    >>with 'istream_iterator' is that the connection between it and the
    >>stream is mutating even after you make a copy of the iterator. You
    >>might get lucky that your stream can be brought back to the same
    >>state somehow, or you might never get lucky, and the stream, once it
    >>has been read, can never go back to its beginning...
    >>
    >>Why do you need to do that, anyway?

    >
    > [snip]
    >
    > I didn't need that, but I came across strange (to me) behavior of copy() while preparing my reply to thread
    > http://groups-beta.google.com/group/comp.lang.c /browse_thread/thread/43ed64bb7a94fa3a/
    >
    > Now I would like to understand this situation.


    If you feel like it, dig in the source of the C++ library (or libraries)
    you're using. It seems that since 'copy' is a template, it probably gets
    its arguments in the form of references (and not objects copied due to
    passing by value). If it's so, the objects change while 'copy' does its
    thing. How they change you can also discover by looking at the code. If
    you find it interesting/revealing/puzzling, do post again.

    You could also experiment with passing by value:

    ...
    void foo(istream_iterator b, istream_iterator e)
    {
    std::copy(b, e, ...
    }

    int main()
    {
    ...
    foo(b, e);
    // reset the stream
    std::copy(b, e, ...
    }

    and see if it makes any difference...

    V
    Victor Bazarov, Jul 21, 2004
    #6
  7. Alex Vinokur

    tom_usenet Guest

    On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
    <> wrote:
    >int main ()
    >{
    >ifstream f("foo.in", ios_base::binary);
    > assert (f);
    >istream_iterator<string> b(f), e;
    >
    > cout << "(1) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > cout << "(2) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > return 0;
    >}
    >(1) File : abc xyz ijk pqr
    >(2) File : abc
    >Why do two copy()'s produce different output?


    When you take a copy of an input iterator, the original one is still
    affected by changes to the copy. istream_iterator can only be used for
    1-pass algorithms. Rewinding the stream and then constructing a new
    iterator from the stream is the only safe way to do a second pass.
    e.g. something like:


    int main ()
    {
    ifstream f("foo.in", ios_base::binary);
    assert (f);
    istream_iterator<string> b(f), e;

    cout << "(1) File : ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;

    f.seekg(0, std::ios_base::beg);
    b = istream_iterator<string>(f);

    cout << "(2) File : ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;

    return 0;
    }

    Tom
    tom_usenet, Jul 22, 2004
    #7
  8. Alex Vinokur

    Alex Vinokur Guest

    "tom_usenet" <> wrote in message news:...
    > On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
    > <> wrote:
    > >int main ()
    > >{
    > >ifstream f("foo.in", ios_base::binary);
    > > assert (f);
    > >istream_iterator<string> b(f), e;
    > >
    > > cout << "(1) File : ";
    > > copy (b, e, ostream_iterator<string> (cout, " "));
    > > cout << endl;
    > >
    > > cout << "(2) File : ";
    > > copy (b, e, ostream_iterator<string> (cout, " "));
    > > cout << endl;
    > >
    > > return 0;
    > >}
    > >(1) File : abc xyz ijk pqr
    > >(2) File : abc
    > >Why do two copy()'s produce different output?

    >
    > When you take a copy of an input iterator, the original one is still
    > affected by changes to the copy. istream_iterator can only be used for
    > 1-pass algorithms. Rewinding the stream and then constructing a new
    > iterator from the stream is the only safe way to do a second pass.
    > e.g. something like:
    >
    >
    > int main ()
    > {
    > ifstream f("foo.in", ios_base::binary);
    > assert (f);
    > istream_iterator<string> b(f), e;
    >
    > cout << "(1) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > f.seekg(0, std::ios_base::beg);
    > b = istream_iterator<string>(f);


    It doesn't help.

    >
    > cout << "(2) File : ";
    > copy (b, e, ostream_iterator<string> (cout, " "));
    > cout << endl;
    >
    > return 0;
    > }
    >
    > Tom


    Here is some program which demonstrates behavior of istream_iterator.

    ====== File foo.cpp : BEGIN ======
    #include <cassert>
    #include <string>
    #include <iostream>
    #include <iterator>
    #include <fstream>
    using namespace std;

    int main ()
    {
    ifstream f("foo.in", ios::binary);
    assert (f);

    cout << "Before istream_iterator : tellg() = " << f.tellg() << endl;
    cout << endl;

    istream_iterator<string> b(f), e;
    cout << "--- First ---" << endl;
    cout << "After istream_iterator : tellg() = " << f.tellg() << endl;


    cout << "Output-1.1 = ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << "After first copy : tellg() = " << f.tellg() << endl;
    cout << "Output-1.2 = ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << endl;


    cout << "--- Second ---" << endl;
    f.clear();
    f.seekg(0, ios::beg);
    cout << "After clear and seekg : tellg() = " << f.tellg() << endl;


    cout << "Output-2.1 = ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << "After second copy : tellg() = " << f.tellg() << endl;
    cout << endl;


    cout << "--- Third ---" << endl;
    f.clear();
    f.seekg(0, ios::beg);
    cout << "After clear and seekg : tellg() = " << f.tellg() << endl;
    b++;
    cout << "After b++ : tellg() = " << f.tellg() << endl;


    cout << "Output-3.1 = ";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << "After third copy : tellg() = " << f.tellg() << endl;
    cout << endl;


    return 0;
    }
    ====== File foo.cpp : END ========


    ====== Compilation & Run : BEGIN ======

    $ g++ --version
    g++ (GCC) 3.3.1 (cygming special)
    [---omitted---]

    $ g++ foo.cpp

    $ a

    Before istream_iterator : tellg() = 0

    --- First ---
    After istream_iterator : tellg() = 3
    Output-1.1 = aaa bbb ccc ddd
    After first copy : tellg() = -1
    Output-1.2 = aaa

    --- Second ---
    After clear and seekg : tellg() = 0
    Output-2.1 = aaa aaa bbb ccc ddd
    After second copy : tellg() = -1

    --- Third ---
    After clear and seekg : tellg() = 0
    After b++ : tellg() = 3
    Output-3.1 = aaa bbb ccc ddd
    After third copy : tellg() = -1

    ====== Compilation & Run : END ========


    --
    Alex Vinokur
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Jul 22, 2004
    #8
  9. Alex Vinokur wrote:
    > "tom_usenet" <> wrote in message news:...
    >
    >>On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
    >><> wrote:
    >>
    >>>int main ()
    >>>{
    >>>ifstream f("foo.in", ios_base::binary);
    >>> assert (f);
    >>>istream_iterator<string> b(f), e;
    >>>
    >>> cout << "(1) File : ";
    >>> copy (b, e, ostream_iterator<string> (cout, " "));
    >>> cout << endl;
    >>>
    >>> cout << "(2) File : ";
    >>> copy (b, e, ostream_iterator<string> (cout, " "));
    >>> cout << endl;
    >>>
    >>> return 0;
    >>>}
    >>>(1) File : abc xyz ijk pqr
    >>>(2) File : abc
    >>>Why do two copy()'s produce different output?

    >>
    >>When you take a copy of an input iterator, the original one is still
    >>affected by changes to the copy. istream_iterator can only be used for
    >>1-pass algorithms. Rewinding the stream and then constructing a new
    >>iterator from the stream is the only safe way to do a second pass.
    >>e.g. something like:
    >>
    >>
    >>int main ()
    >>{
    >> ifstream f("foo.in", ios_base::binary);
    >> assert (f);
    >> istream_iterator<string> b(f), e;
    >>
    >> cout << "(1) File : ";
    >> copy (b, e, ostream_iterator<string> (cout, " "));
    >> cout << endl;
    >>
    >> f.seekg(0, std::ios_base::beg);
    >> b = istream_iterator<string>(f);

    >
    >
    > It doesn't help.


    You probably also need to do

    f.clear();

    before f.seekg( ..

    Once the EOF is reached, the stream becomes non-responsive until
    you clear its error state.

    V

    >
    >
    >> cout << "(2) File : ";
    >> copy (b, e, ostream_iterator<string> (cout, " "));
    >> cout << endl;
    >>
    >> return 0;
    >>}
    >>
    >>Tom

    >
    > [...]
    Victor Bazarov, Jul 22, 2004
    #9
  10. Alex Vinokur

    Alex Vinokur Guest

    "Victor Bazarov" <> wrote in message news:lGALc.36$09.us.to.verio.net...
    [snip]
    > If you feel like it, dig in the source of the C++ library (or libraries)
    > you're using. It seems that since 'copy' is a template, it probably gets
    > its arguments in the form of references (and not objects copied due to
    > passing by value). If it's so, the objects change while 'copy' does its
    > thing. How they change you can also discover by looking at the code. If
    > you find it interesting/revealing/puzzling, do post again.
    >
    > You could also experiment with passing by value:
    >
    > ...
    > void foo(istream_iterator b, istream_iterator e)
    > {
    > std::copy(b, e, ...
    > }
    >
    > int main()
    > {
    > ...
    > foo(b, e);
    > // reset the stream
    > std::copy(b, e, ...
    > }
    >
    > and see if it makes any difference...
    >
    > V



    We can see that there is no difference between passing by value and passing by reference because
    a position of the pointer in istream 'f' (not istream_iterator 'b') determines such behavior.

    ====== foo.cpp : BEGIN ======
    #include <cassert>
    #include <string>
    #include <iostream>
    #include <iterator>
    #include <fstream>
    using namespace std;

    void copy_by_value(istream_iterator<string> b, istream_iterator<string> e)
    {
    copy (b, e, ostream_iterator<string> (cout, " "));
    }

    void copy_by_ref(const istream_iterator<string>& b, const istream_iterator<string>& e)
    {
    copy (b, e, ostream_iterator<string> (cout, " "));
    }

    void test_by_value()
    {
    cout << "=== test_by_value ===" << endl;
    ifstream f("foo.in", ios_base::binary);
    assert (f);
    cout << "Before istream_iterator : tellg() = " << f.tellg() << endl;
    istream_iterator<string> b(f), e;
    cout << "After istream_iterator : tellg() = " << f.tellg() << endl;
    cout << "Output-1 =";
    copy_by_value (b, e);
    cout << endl;
    cout << "After copy_by_value : tellg() = " << f.tellg() << endl;

    cout << "Output-2 =";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << endl;
    }

    void test_by_ref()
    {
    cout << "=== test_by_ref ===" << endl;
    ifstream f("foo.in", ios_base::binary);
    assert (f);
    cout << "Before istream_iterator : tellg() = " << f.tellg() << endl;
    istream_iterator<string> b(f), e;
    cout << "After istream_iterator : tellg() = " << f.tellg() << endl;
    cout << "Output-1 =";
    copy_by_ref (b, e);
    cout << endl;
    cout << "After copy_by_ref : tellg() = " << f.tellg() << endl;

    cout << "Output-2 =";
    copy (b, e, ostream_iterator<string> (cout, " "));
    cout << endl;
    cout << endl;
    }


    int main ()
    {
    test_by_value();
    test_by_ref();

    return 0;
    }
    ====== foo.cpp : END ========


    ###### Run : BEGIN ######

    === test_by_value ===
    Before istream_iterator : tellg() = 0
    After istream_iterator : tellg() = 3
    Output-1 =aaa bbb ccc ddd
    After copy_by_value : tellg() = -1
    Output-2 =aaa

    === test_by_ref ===
    Before istream_iterator : tellg() = 0
    After istream_iterator : tellg() = 3
    Output-1 =aaa bbb ccc ddd
    After copy_by_ref : tellg() = -1
    Output-2 =aaa


    ###### Run : END ######



    --
    Alex Vinokur
    http://mathforum.org/library/view/10978.html
    http://sourceforge.net/users/alexvn
    Alex Vinokur, Jul 24, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Bill Rudolph

    istream_iterator question

    Bill Rudolph, Aug 14, 2003, in forum: C++
    Replies:
    4
    Views:
    544
    Bill Rudolph
    Aug 15, 2003
  2. Chris Mantoulidis
    Replies:
    2
    Views:
    410
  3. Alex Vinokur

    istream_iterator & copying files

    Alex Vinokur, Apr 19, 2004, in forum: C++
    Replies:
    10
    Views:
    1,229
    Alex Vinokur
    Apr 20, 2004
  4. NPC

    istream_iterator<>

    NPC, May 13, 2004, in forum: C++
    Replies:
    3
    Views:
    1,288
    tom_usenet
    May 14, 2004
  5. ben

    about istream_iterator

    ben, May 17, 2005, in forum: C++
    Replies:
    2
    Views:
    412
Loading...

Share This Page