Help with this istringstream

I'm currently working through the C++ Primer book and I'm at istringstream section and there is an exercise as follows:

"The program in this section defined its istringstream object inside the outer while loop. What changes would you need to make if record were defined outside that loop? Rewrite the program, moving the definition of record outside the while, and see whether you thought of all the changes that are needed."

The program in question is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
    struct PersonInfo {
        string name;
        vector<string> phones;
    };

    string line, word;  
    vector<PersonInfo> people; 

    while (getline(cin, line)) {
        PersonInfo info;      
        istringstream record(line); 
        record >> info.name;  
        while (record >> word)        
            info.phones.push_back(word);  
        people.push_back(info); 
    }

/// I made the following for printing out the information to make sure it works right.
    for (auto i = people.begin(); i != people.end(); ++i) { 
        cout << i->name << " ";
        for (auto j = i->phones.begin(); j != i->phones.end(); ++j) { 
            cout << *j << " ";
        }
        cout << endl;
    }
    return 0;
}




My solution to the problem was to just move the istringstream definition before the while loop and bind it inside using str():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
    struct PersonInfo {
        string name;
        vector<string> phones;
    };

    string line, word;  
    vector<PersonInfo> people; 
    istringstream record; // Moved definition up here and kept it unbound.
    while (getline(cin, line)) {
        PersonInfo info;      
        record.str(line); // Bind line to record
        record >> info.name;  
        while (record >> word)        
            info.phones.push_back(word);  
        people.push_back(info); 
    }

/// I made the following for printing out the information to make sure it works right.
    for (auto i = people.begin(); i != people.end(); ++i) { 
        cout << i->name << " ";
        for (auto j = i->phones.begin(); j != i->phones.end(); ++j) { 
            cout << *j << " ";
        }
        cout << endl;
    }
    return 0;
}


The version in the book with the definition in the while loop works just fine. It prints the results out exactly as they went in. However after I made the changes the exercise wanted, it only wants to read the first line. On further inspection I found out the state of the stream changes to no longer be good after the first getline that is read in. If I manually use clear() on record before another >>, the program works fine. I'm not sure if that is the solution though. I don't know why the state of the stream is not good after the first read?

Any help is appreciated. Thanks.
I don't know why the state of the stream is not good after the first read?


while (record >> word) // read until an operation fails and the state changes.

Because that's what you tell it to do?
But why does the first version work, while the second version doesn't when the istringstream is declared outside the first while loop.
In the first version, you have a new istringstream every iteration of the loop.
Ahh yeah, so I suppose by creating a a new one every loop, it's in a good state every time. So I take it using clear() is the solution?

Edit: Yeah after looking more closely at this, I didn't realize that on the second iteration of the outer while loop, the state of record would still be eof/fail.

Thanks for the help.
Last edited on
Topic archived. No new replies allowed.