简体   繁体   中英

Unexpected stringstream behavior

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()) ?

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 .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM