Reputation: 2429
Consider the following code:
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
stringstream ss;
ss << string("12");
int h;
ss >> h;
cout << h << endl;
ss.str(string("")); // clear the content of ss
ss << string("30");
int m;
ss >> m;
cout << m << endl;
return 0;
}
Running the above code yields some random output:
12
0
At some other times, the following output is observed:
12
4
I expected the output to be simply:
12
30
Why did I get the unexpected results?
Also, what should be the best way to parse a string s
to int i
without necessary C++11 support? Should it be int i = atoi(s.c_str())
?
Upvotes: 2
Views: 830
Reputation: 271
For those who're here with something similar to the above but not exactly, I found that when you've got a stream in a scenario where you need to re-use it (like in a while loop), the easiest way to avoid head-aches (in addition to ss.clear
) is to create a new stream each time. For example:
int GetInteger(){
cout << "Enter an int: " << endl;
string userInput;
while (true){
stringstream ss;
getline(cin,userInput);
ss << userInput;
//Making sure that an int was passed
int result;
if (ss >> result){
//Making sure that there is no extra stuff after
string extra;
if (ss >> extra){
cout << "Unexpected stuff at end of input: " << extra << endl;
} else{
return result;
}
} else {
cout << "Number you entered is not an INT. Please enter an integer" << endl;
}
cout << "Retry: " << endl;
// ss.clear();
}
}
So every time the user enters an invalid input, at the start of the while loop, I create a new stringstream object. While researching my function's undefined behavior, I found this question that has a similar example.
Upvotes: 0
Reputation: 110648
When you extract 12
from the stream, you reach the end of it, which puts it in a bad state. Any further extractions will fail. You need to call ss.clear()
around the time you clear its contents.
If you had checked the success of your extractions, you would have avoided this problem. I generally expect to see any extraction from a stream as some kind of condition.
And yes, using string streams to parse strings as integers is a perfectly reasonable way to do it pre-C++11. I would prefer it over using atoi
. For anybody who wants to know the C++11 way, use std::stoi.
Upvotes: 6