trouble in understanding istream_iterator

Discussion in 'C++' started by subramanian100in@yahoo.com, India, May 7, 2010.

  1. , India

    , India Guest

    I am using g++ 3.4.3

    Consider the following program x.cpp:

    #include <cstdlib>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    #include <iterator>

    using namespace std;

    int main()
    {
    istream_iterator<string> isi(cin);
    istream_iterator<string> eos;

    vector<string> c(isi, eos);

    cout << "Displaying input contents:" << endl;
    cout << "--------------------------" << endl;

    copy(c.begin(),
    c.end(),
    ostream_iterator<string>(cout, "\n"));

    cout << endl;

    if (isi == eos)
    cout << "end of input stream reached" << endl;
    else
    cout << "eos not reached" << endl;

    string str;

    if (cin >> str)
    cout << "string read from cin: " << str << endl;
    else
    cout << "Unable to read a string from cin" << endl;

    cout << endl;

    vector<string> d(isi, eos);

    cout << "Displaying the input second time:" << endl;
    cout << "---------------------------------" << endl;

    copy(d.begin(),
    d.end(),
    ostream_iterator<string>(cout, "\n"));

    return EXIT_SUCCESS;
    }

    When I run this program with the following input
    1
    2
    3

    the following is printed:

    Displaying input contents:
    --------------------------
    1
    2
    3

    eos not reached
    Unable to read a string from cin

    Displaying the input second time:
    ---------------------------------
    1

    Kindly correct me whereever I am wrong in the following:

    In the above program, consider the statement:
    vector<string> c(isi, eos);
    This vector ctor will construct the object 'c' with three input values
    namely '1', '2', '3' which were entered from the standard input. After
    this ctor statement, there will NOT be any input contents left in cin.
    Am I correct ?
    The first 'copy' algorithm will copy the contents of 'c' onto the
    standard output. Now consider the statement
    if (isi == eos)
    Here I thought 'isi' should be equal to 'eos' because there is no
    content left in 'cin'. But on the contrary, 'eos not reached' is
    printed. I am unable to understand the reason for this.

    Now consider the statement
    if (cin >> str)
    For this, the control goes to the else part(because there is no
    content left in the stanadard input stream 'cin') and prints:

    Unable to read a string from cin

    This is as expected.

    Now consder the vector object:
    vector<string> d(isi, eos);
    Since there is no content left in 'cin', the vector object 'd' should
    be empty I thought. However, on the contrary, the subsequent 'copy'
    algorithm prints:

    1

    I am unable to understand how the second vector object d's ctor was
    able to read 'isi' to fetch the value '1'. In other words, where does
    this value '1' come from ?

    Kindly explain.

    Thanks
    V.Subramanian
    , India, May 7, 2010
    #1
    1. Advertising

  2. , India

    Kai-Uwe Bux Guest

    , India wrote:

    > I am using g++ 3.4.3
    >
    > Consider the following program x.cpp:
    >
    > #include <cstdlib>
    > #include <iostream>
    > #include <string>
    > #include <vector>
    > #include <algorithm>
    > #include <iterator>
    >
    > using namespace std;
    >
    > int main()
    > {
    > istream_iterator<string> isi(cin);
    > istream_iterator<string> eos;
    >
    > vector<string> c(isi, eos);
    >
    > cout << "Displaying input contents:" << endl;
    > cout << "--------------------------" << endl;
    >
    > copy(c.begin(),
    > c.end(),
    > ostream_iterator<string>(cout, "\n"));
    >
    > cout << endl;
    >
    > if (isi == eos)
    > cout << "end of input stream reached" << endl;
    > else
    > cout << "eos not reached" << endl;


    This test is bogus. The variable isi has not changed.


    > string str;
    >
    > if (cin >> str)
    > cout << "string read from cin: " << str << endl;
    > else
    > cout << "Unable to read a string from cin" << endl;
    >
    > cout << endl;
    >
    > vector<string> d(isi, eos);
    >
    > cout << "Displaying the input second time:" << endl;
    > cout << "---------------------------------" << endl;
    >
    > copy(d.begin(),
    > d.end(),
    > ostream_iterator<string>(cout, "\n"));
    >
    > return EXIT_SUCCESS;
    > }
    >
    > When I run this program with the following input
    > 1
    > 2
    > 3
    >
    > the following is printed:
    >
    > Displaying input contents:
    > --------------------------
    > 1
    > 2
    > 3
    >
    > eos not reached
    > Unable to read a string from cin
    >
    > Displaying the input second time:
    > ---------------------------------
    > 1
    >
    > Kindly correct me whereever I am wrong in the following:
    >
    > In the above program, consider the statement:
    > vector<string> c(isi, eos);
    > This vector ctor will construct the object 'c' with three input values
    > namely '1', '2', '3' which were entered from the standard input. After
    > this ctor statement, there will NOT be any input contents left in cin.
    > Am I correct ?


    Yes.


    > The first 'copy' algorithm will copy the contents of 'c' onto the
    > standard output. Now consider the statement
    > if (isi == eos)
    > Here I thought 'isi' should be equal to 'eos' because there is no
    > content left in 'cin'. But on the contrary, 'eos not reached' is
    > printed. I am unable to understand the reason for this.


    You did not change the value of isi. Passing as the first argument to the
    constructor of the vector is by value.


    > Now consider the statement
    > if (cin >> str)
    > For this, the control goes to the else part(because there is no
    > content left in the stanadard input stream 'cin') and prints:
    >
    > Unable to read a string from cin
    >
    > This is as expected.


    Yes.


    > Now consder the vector object:
    > vector<string> d(isi, eos);
    > Since there is no content left in 'cin', the vector object 'd' should
    > be empty I thought. However, on the contrary, the subsequent 'copy'
    > algorithm prints:
    >
    > 1
    >
    > I am unable to understand how the second vector object d's ctor was
    > able to read 'isi' to fetch the value '1'. In other words, where does
    > this value '1' come from ?


    Undefined behavior. The input iterator isi has been invalidated in the first
    pass through the input, but the now invalid value is still there (in the
    variable isi). [24.1.1./3] warns that algorithms using input iterators
    should be single pass.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, May 7, 2010
    #2
    1. Advertising

  3. , India

    , India Guest

    * Kai-Uwe Bux <> wrote:
    > , India wrote:
    > > I am using g++ 3.4.3

    >
    > > Now consder the vector object:
    > > vector<string> d(isi, eos);
    > > Since there is no content left in 'cin', the vector object 'd' should
    > > be empty I thought. However, on the contrary, the subsequent 'copy'
    > > algorithm prints:

    >
    > > 1

    >
    > > I am unable to understand how the second vector object d's ctor was
    > > able to read 'isi' to fetch the value '1'. In other words, where does
    > > this value '1' come from ?

    >
    > Undefined behavior. The input iterator isi has been invalidated in the first
    > pass through the input, but the now invalid value is still there (in the
    > variable isi). [24.1.1./3] warns that algorithms using input iterators
    > should be single pass.
    >
    > Best
    >
    > Kai-Uwe Bux


    In the above reply, the following sentence is present:
    "The input iterator isi has been invalidated in the first pass through
    the input"
    Here does 'first pass' refer to the statement
    vector<string> c(isi, eos);

    Also, kindly clarify how 'isi' could be invalidated at the calling
    point of the ctor since we are passing 'isi' by value to the ctor.

    Consider the statement
    vector<string> d(isi, eos);
    Here do you mean to say 'isi' is traversed second time ?

    I thought, only within the same algorithm we should not try traverse
    the input iterator multiple times. Since we are passing 'isi' by value
    to vector ctor in the construction of the objects 'c' and 'd', will
    that amount to traversing 'isi' multiple times ?

    Since we are passing the input iterator 'isi' by value to the vector
    ctor, inside the ctor, only the local copy of that input iterator will
    be incremented. Since we do this once in the construction of 'c' and
    second time during the construction of 'd', at the calling point of
    the ctors we are not traversing multiple times. Is this understanding
    of mine is correct?

    I am unable to understand this. Kindly clarify, if needed with an
    example.

    Thanks
    V.Subramanian
    , India, May 9, 2010
    #3
  4. , India

    Kai-Uwe Bux Guest

    , India wrote:

    > * Kai-Uwe Bux <> wrote:
    >> , India wrote:
    >> > I am using g++ 3.4.3

    >>
    >> > Now consder the vector object:
    >> > vector<string> d(isi, eos);
    >> > Since there is no content left in 'cin', the vector object 'd' should
    >> > be empty I thought. However, on the contrary, the subsequent 'copy'
    >> > algorithm prints:

    >>
    >> > 1

    >>
    >> > I am unable to understand how the second vector object d's ctor was
    >> > able to read 'isi' to fetch the value '1'. In other words, where does
    >> > this value '1' come from ?

    >>
    >> Undefined behavior. The input iterator isi has been invalidated in the
    >> first pass through the input, but the now invalid value is still there
    >> (in the variable isi). [24.1.1./3] warns that algorithms using input
    >> iterators should be single pass.
    >>
    >> Best
    >>
    >> Kai-Uwe Bux

    >
    > In the above reply, the following sentence is present:
    > "The input iterator isi has been invalidated in the first pass through
    > the input"
    > Here does 'first pass' refer to the statement
    > vector<string> c(isi, eos);


    Yes.


    > Also, kindly clarify how 'isi' could be invalidated at the calling
    > point of the ctor since we are passing 'isi' by value to the ctor.


    See how Table 72 of the standard specifies the post-condition of ++r:

    post: any copies of the previous value of r are no longer required either
    to be dereferenceable or to be in the domain of ==

    > Consider the statement
    > vector<string> d(isi, eos);
    > Here do you mean to say 'isi' is traversed second time ?


    Yes.

    > I thought, only within the same algorithm we should not try traverse
    > the input iterator multiple times.


    Depends what you mean by "algorithm". The post-condition from above makes it
    pretty clear, that the program as a whole is the "algorithm".

    > Since we are passing 'isi' by value
    > to vector ctor in the construction of the objects 'c' and 'd', will
    > that amount to traversing 'isi' multiple times ?


    Yes.

    > Since we are passing the input iterator 'isi' by value to the vector
    > ctor, inside the ctor, only the local copy of that input iterator will
    > be incremented. Since we do this once in the construction of 'c' and
    > second time during the construction of 'd', at the calling point of
    > the ctors we are not traversing multiple times. Is this understanding
    > of mine is correct?


    No.

    See the post-condition above. Note in particular how is says "any copies".
    That way, even though isi retains its value, it is still invalidated for
    further use.

    > I am unable to understand this. Kindly clarify, if needed with an
    > example.


    Your example is just fine. It illustrates the provisions of the standard by
    exhibiting undefined behavior in exactly the right place.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, May 9, 2010
    #4
  5. , India

    , India Guest

    * Kai-Uwe Bux <> wrote:
    > , India wrote:
    > > * Kai-Uwe Bux <> wrote:
    > >> , India wrote:
    > >> > I am using g++ 3.4.3


    Now consider the following modified program x.cpp:

    #include <cstdlib>
    #include <iostream>
    #include <string>
    #include <vector>
    #include <algorithm>
    #include <iterator>

    using namespace std;

    int main()
    {
    istream_iterator<string> isi(cin);
    istream_iterator<string> eos;

    vector<string> c(isi, eos);

    cout << "Displaying input contents:" << endl;
    cout << "--------------------------" << endl;

    copy(c.begin(),
    c.end(),
    ostream_iterator<string>(cout, "\n"));

    cout << endl;

    cin.clear();

    vector<string> d(isi, eos);

    cout << "Displaying the input second time:" << endl;
    cout << "---------------------------------" << endl;

    copy(d.begin(),
    d.end(),
    ostream_iterator<string>(cout, "\n"));

    return EXIT_SUCCESS;

    }

    In this modified program I have added
    cin.clear();
    between the first vector object construction viz:
    vector<string> c(isi, eos);
    and the second vector object construction viz:
    vector<string> d(isi, eos);

    In this case also, is the istream_iterator 'isi' invalidated(when I
    pass it to the ctor for 'd') thereby invoking undefined behavior ?

    Kindly explain.

    Thanks
    V.Subramanian
    , India, May 10, 2010
    #5
  6. , India

    Kai-Uwe Bux Guest

    , India wrote:

    > * Kai-Uwe Bux <> wrote:
    >> , India wrote:
    >> > * Kai-Uwe Bux <> wrote:
    >> >> , India wrote:
    >> >> > I am using g++ 3.4.3

    >
    > Now consider the following modified program x.cpp:
    >
    > #include <cstdlib>
    > #include <iostream>
    > #include <string>
    > #include <vector>
    > #include <algorithm>
    > #include <iterator>
    >
    > using namespace std;
    >
    > int main()
    > {
    > istream_iterator<string> isi(cin);
    > istream_iterator<string> eos;
    >
    > vector<string> c(isi, eos);
    >
    > cout << "Displaying input contents:" << endl;
    > cout << "--------------------------" << endl;
    >
    > copy(c.begin(),
    > c.end(),
    > ostream_iterator<string>(cout, "\n"));
    >
    > cout << endl;
    >
    > cin.clear();
    >
    > vector<string> d(isi, eos);
    >
    > cout << "Displaying the input second time:" << endl;
    > cout << "---------------------------------" << endl;
    >
    > copy(d.begin(),
    > d.end(),
    > ostream_iterator<string>(cout, "\n"));
    >
    > return EXIT_SUCCESS;
    >
    > }
    >
    > In this modified program I have added
    > cin.clear();
    > between the first vector object construction viz:
    > vector<string> c(isi, eos);
    > and the second vector object construction viz:
    > vector<string> d(isi, eos);
    >
    > In this case also, is the istream_iterator 'isi' invalidated(when I
    > pass it to the ctor for 'd') thereby invoking undefined behavior ?


    Yes, the behavior is still undefined: the call cin.clear() does not change
    the fact that you are dereferencing a copy of isi in the construction of d
    after incrementing a copy during construction of c.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, May 10, 2010
    #6
    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,287
    tom_usenet
    May 14, 2004
  5. Alex Vinokur

    Copying with istream_iterator

    Alex Vinokur, Jul 21, 2004, in forum: C++
    Replies:
    9
    Views:
    573
    Alex Vinokur
    Jul 24, 2004
Loading...

Share This Page