1

Wondering what's going on here. I've tried to push this through gdb but can't seem to get a debug version / code of libstdc++, so hoping someone who knows their streams can help? In the code below, the key bit is the while loop:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <sstream>
using namespace std;
void printer(int i) {
        cout << i << ", ";
}
int main ()
{
        string s;
        getline(cin, s);
        stringstream input(s);
        vector<int> v1;
        int i;
        while (!input.fail())
        {
                input >> i;
                v1.push_back(i);
        } 
        for_each(v1.begin(), v1.end(), printer);
        return 0;
}

When I run this and supply a number, this appears to add that number twice to the vector. If I change the while loop's condition to eof() (as opposed to fail()) everything behaves as I'd have expected.

So given the extraction operator>> is supposed to extract values from a stream, how is it possible that successive calls keep producing the result?

I'm guessing that I'm not thinking about this quite right (it's 2:30am localtime so that might have something to do with it!)

Using gcc version 4.9.2 (Ubuntu 4.9.2-0ubuntu1~12.04)

aho
  • 194
  • 11

1 Answers1

4

This is a thinly disguised version of the usual incorrect use of eof() bug.

The loop should be:

while ( input >> i )
    v1.push_back(i);

In your actual code you still push_back(i) even after the failed read.

In the version with eof() it may or may not actually set the eof flag while reading the previous value; you can't rely on what you are observing.

Community
  • 1
  • 1
M.M
  • 130,300
  • 18
  • 171
  • 314
  • I see - your latest edit answers my question of "why does it appear to work with eof()?" - thanks - basically if you're ever gonna extract from a stream in a loop, the extraction happening in the loop condition is the canonical way I take it? – aho Nov 11 '15 at 02:42
  • @aho If not canonical, it is at the very least extremely highly recommended. – user4581301 Nov 11 '15 at 02:52
  • 1
    @aho it's usually a good thing to do, but for some data types you could read a partial value then fail and hit eof at the same time: with the stream state flags then left the same as for an eof condition without a partial value, it's hard to recognise and react to the bogus partial value. For example, if you stream to a `double` and the stream only has `5E` - it's a failing conversion as well as eof. For those cases when you care, you can use `while (input >> std::skipws && !input.eof() && input >> my_double)`, then the fail bit will only get set if parsing failed. – Tony Delroy Nov 11 '15 at 04:40