Search code examples
xcodestandard-libraryllvm-clanglibc++

Xcode 4.4 Lion inconsistent newline behavior in C++ with GCC vs LLVM


I've been using the following bit of code for years to consume characters from cin up and including the next newline.

void skip_rest_of_line()
{
    while (cin.get() != '\n') {}
}

I would call this after a catching an exception and clearing the cin state, as in:

catch (Error& error) {
    cout << error.msg << endl;
    cin.clear();
    skip_rest_of_line();
    }

The next read from cin skips the remaining newline as whitespace.

I've just changed to Xcode 4.4.1 under Lion. Using LLVM GCC 4.2 GNU++98, libstdc++(GNU C++ standard library), it works like it always did.

But using Apple LLVM Compiler 4.0, c++11, libc++ (LLVM C++ standard library with C++11 support) it looks like there are multiple problems with recognizing the newline. The same code as above requires a second return keystroke to satisfy the loop! The same problem appears with the alternative:

cin.ignore(numeric_limits<streamsize>::max(), '\n');

Finally, using getchar instead of cin.get() in the while loop works like it always did!

Is this a bug in libc++? Or have I missed something either in Xcode or C++11?

In response to Howard Hinnant, here is a little test case that shows what happens without any exceptions, etc. in the picture:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
 for(int count = 0; count < 2; count++) {
    cout << "ready for input: " << endl;
    int i;
    vector<int> v;
    while(cin >> i) {
        v.push_back(i);
        if(i == 3) {
            while(cin.get() != '\n') {}
            break;
            }
        }
    for(auto it = v.begin(); it != v.end();  ++it)
        cout << *it << ' ';
    cout << endl;
}

cout << "done" << endl;
return 0;

}

It reads and saves ints until it's saved a 3, whereupon it reads and discards through the next newline, and then repeats the whole thing, so you can see that the stuff after the 3 gets discarded from the input stream. With Xcode 4.4.1 Lion with GNU++98 || GNU++11, libstd++, I get what I expect when I put in these two lines each terminated by a space followed by a RETURN keystroke:

1 2 3 4 5 
6 7 8 3 

and I get in the output window of Xcode:

ready for input: 
1 2 3 4 5 
1 2 3 
ready for input: 
6 7 8 3 
6 7 8 3 
done

But with C++11, libc++, nothing happens with the first line until I enter a SECOND RETURN keystroke, after both lines of input, but the proper discarding has still happened. So the extra space below after each input line is what the second keystroke looks like.

ready for input: 
1 2 3 4 5 

1 2 3 
ready for input: 
6 7 8 3 

6 7 8 3 
done

The very same behavior happens with using the above cin.ignore call instead of the while loop around cin.get(). So the problem is "Why is the second RETURN keystroke needed?"


Solution

  • I think this is a bug in libc++ on Lion, and fixed on Mountain Lion. But it is difficult to be certain without a complete test case.

    Update

    Thanks for the test case. Confirmed bug on Lion and fixed on Mountain Lion.