0

I was recently reading a C++ textbook (Accelerated C++) and the author wants to read input data of the form:

name1 double double double double ... 
name2 double double double double ...
                    ^ all doubles from here on out will go into a vector

The author's idea is to do do something like read from cin until the stream fails, which it will do either because the input is finished, or because we try reading name2 as a double which will put the stream into a fail state. In regards to this he says

In either case, then, we would like to pretend that we never saw whatever followed the last homework grade. Such pretense turns out to be easy: if we encountered something that wasn't a grade, the library will have left it unread for the next input attempt. Therefore all we need to do is tell the library to disregard whatever condition caused the input attempt to fail, be it eof or invalid input.

My question relates to the bolded part. The author seems to be implying that a failed attempt at reading from cin will not discard the token that it failed on, but rather leave it in the stream. However, I wrote a program to test this and this does't seem to be the case:

Input data (i've put it all on one line for simplicity):

p1 90 91 92 93 94 p2 81 82 83 84 85

Program:

using std::cout;    using std::cin;
using std::endl;    using std::string;

int main() {

    while(cin) {
        string name, midterm, final;
        cin >> name >> midterm >> final;
        double x;
        cout << endl <<  "Name: " << name
             << ", Mid: " << midterm
             << ", Final: " << final << "\t"
             << "Homework: {";
        while(cin >> x) {
            std::cout << x << ", ";
        }
        cout << "}" << endl;

        if(cin.fail()) {
            cin.clear();
            string f;
            cin >> f;
            cout << "Stream failed - next token: "  << f << endl;
        }
    }

}

Output:

Name: p1, Mid: 90, Final: 91    Homework: {92, 93, 94, }
Stream failed - next token: 81

Name: 82, Mid: 83, Final: 84    Homework: {85,  

Edit:

This seems to be a machine specific thing; in particular a Mac issue. I tried running the code on another Linux and Mac machine and it worked on the Linux machine but not on the Mac.

My question then is how is it possible that this code could be platform dependent.

gowrath
  • 3,136
  • 2
  • 17
  • 32
  • And what did you type in, and what did it print? – user253751 Mar 26 '17 at 23:49
  • @immibis Added output – gowrath Mar 26 '17 at 23:54
  • In this case the read does not fail. The program is just waiting for you to input more data. – cpplearner Mar 27 '17 at 00:12
  • When replacing `cin` with `istringstream`, [it works](http://coliru.stacked-crooked.com/a/e1b4623946271184) as author describes. – zett42 Mar 27 '17 at 00:13
  • 1
    @cpplearner I believe read does indeed fail, which is why the if block is entered. – gowrath Mar 27 '17 at 00:14
  • @zett42 Yes I tried that. I know a better way to do this would be to use getline() but I'm just curious now. – gowrath Mar 27 '17 at 00:15
  • It also works when giving your original sample program input via `stdin` redirection. [Example](https://ideone.com/NRZcZU). So I guess it has something to do with how you manually enter the input. – zett42 Mar 27 '17 at 00:20
  • Can't reproduce the issue even when manually entering the input in the console. So how *exactly* did you enter the tokens, i. e. where did you enter space and/or line break? – zett42 Mar 27 '17 at 00:28
  • @zett42 [Here](https://i.stack.imgur.com/algwg.png) is a screenshot. – gowrath Mar 27 '17 at 00:36
  • @zett42 Interesting. I just tried compiling and running on another machine; works there. How on earth can something like this be machine specific? – gowrath Mar 27 '17 at 00:38
  • Probably because of _[std::cin and std::wcin control input from a stream buffer of implementation-defined type](http://en.cppreference.com/w/cpp/io/cin)_ – zett42 Mar 27 '17 at 00:43
  • @zett42 I suppose so. If you want to make your comments into an answer I will gladly accept it. – gowrath Mar 27 '17 at 01:04
  • Sorry, I won't make an answer based on just a guess. ;-) – zett42 Mar 27 '17 at 01:05
  • As a guess: there might be an issue like http://stackoverflow.com/questions/26334399/what-is-the-result-of-strtod3ex-end-supposed-to-be-what-about-sscanf involved here. Streams can only "unget" one character. And if your Mac implementation somehow believes that `p2` is a valid beginning of a `double` value (`p` can be used in hex floating-point representations), by the time it realizes there's a problem it might be too late to rollback the reads. Of course, `p2` is not a valid representation, but a bug in the implementation might make it believe it is. – AnT stands with Russia Mar 27 '17 at 01:41
  • In any case, can you try using, say, `d2` instead of `p2` on that Mac and see what happens? – AnT stands with Russia Mar 27 '17 at 01:42
  • @AnT So d2 doesn't work but following some experimentation, I think you're on to the right issue. For ex. if it tries parsing "ady", it will unget only up the y, but if it instead tries "yad", it will leave the entire token. I think this is probably because it is considering the first two as hex in the first case but fails early in the second case because y can't be a valid double in any form. – gowrath Mar 27 '17 at 20:00

0 Answers0