csguy
csguy

Reputation: 1474

Using .clear() in string streams (C++)

This is an example from my textbook on using / implementing string streams:

int main() {
   istringstream inSS;       // Input string stream
   string lineString;        // Holds line of text
   string firstName;         // First name
   string lastName;          // Last name
   int    userAge = 0;       // Age
   bool   inputDone = false; // Flag to indicate next iteration

   // Prompt user for input
   cout << "Enter \"firstname lastname age\" on each line" << endl;
   cout << "(\"Exit\" as firstname exits)." << endl << endl;

   // Grab data as long as "Exit" is not entered
   while (!inputDone) {

      // Entire line into lineString
      getline(cin, lineString);

      // Copies to inSS's string buffer
      inSS.clear();                        // <-- HELLO RIGHT HERE
      inSS.str(lineString);

      // Now process the line
      inSS >> firstName;

      // Output parsed values
      if (firstName == "Exit") {
         cout << "   Exiting." << endl;

         inputDone = true;
      }
      else {
         inSS >> lastName;
         inSS >> userAge;

         cout << "   First name: " << firstName << endl;
         cout << "   Last  name: " << lastName << endl;
         cout << "   Age:        " << userAge   << endl;
         cout << endl;
      }
   }

   return 0;
}

I don't understand why inSS.clear(); is necessary. The book states that:

"The statement inSS.clear(); is necessary to reset the state of the stream so that subsequent extractions start from the beginning; the clear resets the stream's state."

How does .clear() cause next extractions to start from the beginning when all it does is "set a new value for the stream's internal error state flags."?

If I remove the statement inSS.clear() from the example above, it doesn't work. For example: Input:

joe shmo 23
alex caruso 21

Output:

   First name: joe
   Last  name: shmo
   Age:        23

   First name: joe
   Last  name: shmo
   Age:        23

This is what I expected to happen when the statement inSS.clear() is removed. My understanding is obviously flawed so please correct me:

Input:

joe shmo 23
alex caruso 21

getline(cin, lineString); extracts joe shmo 23 from the cin stream into lineString and discards /n at the end.

inSS.str(lineString); initializes the string stream buffer to the string lineString.

inSS >> firstName; will extract joe

inSS >> lastName; will extract shmo

inSS >> userAge; will extract 23

Leaving inSS empty and ready to process the next input.

According to how to reuse stringstream

If you don't call clear(), the flags of the stream (like eof) wont be reset, resulting in surprising behaviour

What is this behavior? So, what actually happens and why is .clear() necessary?

Upvotes: 1

Views: 252

Answers (1)

M.M
M.M

Reputation: 141618

After you do inSS >> userAge; the first time, that involves trying to read past the end of the string, since it had to see if there was another digit after the last digit of the age.

This means the eofbit is set on the stream, which means future extractions will fail due to the stream being in an end-of-file state. The clear() call clears this state.

You should find that if you provide an input string the first time around that can extract userAge without hitting the end (e.g. joe shmo 23 foo) then the clear() call is not necessary (but it's still good practice).

BTW it would be good practice to test if (!inSS) to check for errors after inSS >> userAge otherwise you go on to output "garbage" values in the form of whatever values the variables already had, since the read attempt failed.

Upvotes: 1

Related Questions