Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Copying with istream_iterator

Reply
Thread Tools

Copying with istream_iterator

 
 
Alex Vinokur
Guest
Posts: n/a
 
      07-21-2004

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



 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      07-21-2004
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
 
Reply With Quote
 
 
 
 
Alex Vinokur
Guest
Posts: n/a
 
      07-21-2004

"Victor Bazarov" <(E-Mail Removed)> wrote in message news:rzxLc.30$(E-Mail Removed)09.us.to.veri o.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






 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      07-21-2004
Alex Vinokur wrote:
> "Victor Bazarov" <(E-Mail Removed)> wrote in message news:rzxLc.30$(E-Mail Removed)09.us.to.veri o.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
 
Reply With Quote
 
Alex Vinokur
Guest
Posts: n/a
 
      07-21-2004

"Victor Bazarov" <(E-Mail Removed)> wrote in message news:uxzLc.34$(E-Mail Removed)09.us.to.veri o.net...
> Alex Vinokur wrote:
> > "Victor Bazarov" <(E-Mail Removed)> wrote in message news:rzxLc.30$(E-Mail Removed)09.us.to.veri o.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/...d64bb7a94fa3a/

Now I would like to understand this situation.


--
Alex Vinokur
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn




 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      07-21-2004
Alex Vinokur wrote:
> "Victor Bazarov" <(E-Mail Removed)> wrote in message news:uxzLc.34$(E-Mail Removed)09.us.to.veri o.net...
>
>>Alex Vinokur wrote:
>>
>>>"Victor Bazarov" <(E-Mail Removed)> wrote in message news:rzxLc.30$(E-Mail Removed)09.us.to.veri o.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/...d64bb7a94fa3a/
>
> 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
 
Reply With Quote
 
tom_usenet
Guest
Posts: n/a
 
      07-22-2004
On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
<(E-Mail Removed)> 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
 
Reply With Quote
 
Alex Vinokur
Guest
Posts: n/a
 
      07-22-2004

"tom_usenet" <(E-Mail Removed)> wrote in message news:(E-Mail Removed)...
> On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
> <(E-Mail Removed)> 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



 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      07-22-2004
Alex Vinokur wrote:
> "tom_usenet" <(E-Mail Removed)> wrote in message news:(E-Mail Removed)...
>
>>On Wed, 21 Jul 2004 19:58:32 +0300, "Alex Vinokur"
>><(E-Mail Removed)> 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

>
> [...]

 
Reply With Quote
 
Alex Vinokur
Guest
Posts: n/a
 
      07-24-2004

"Victor Bazarov" <(E-Mail Removed)> wrote in message news:lGALc.36$(E-Mail Removed)09.us.to.veri o.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





 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
about istream_iterator ben C++ 2 05-18-2005 03:39 AM
istream_iterator<> NPC C++ 3 05-14-2004 11:41 AM
istream_iterator & copying files Alex Vinokur C++ 10 04-20-2004 07:16 PM
istream_iterator and ostream_iterator problem Chris Mantoulidis C++ 2 12-15-2003 12:14 PM
istream_iterator question Bill Rudolph C++ 4 08-15-2003 07:28 AM



Advertisments