Cin's Buffer: problems with the default attributes

Every newbie eventually comes accross one very obvious problem with cin: they need a way to clear it's buffer. Obviously, many people turn to cin.ignore(), but that function isn't meant for that purpose. Others use API calls.

Well, there is a way, and it's really quite simple:

while(cin.rdbuf()->in_avail() > 0) cin.get();

EXCEPT this does not work! At least not by default..... ;)

You see, I learned today that usually, the standard input and output streams for the C++ and C I/O functions are synced. What this means is that none of the standard input functions manages it's own, completely independent buffer. This is why in_avail() will read zero, even though it's definitely more than zero...

The fix? Quite simple:

1
2
3
4
5
6
//a single call in main should do the trick:
int main(int count, char **vec)
{
    cin.sync_with_stdio(false); //tells cin not to sync with the C io functions' buffers
    return 0;
}


Now try the code to clear cin's buffer. It works! That's because cin (the C++ way) doesn't sync with stdin(the C way) anymore, and manages a completely independent buffer. It then becomes a trivial action to clear input.

I just thought this was somthing everyone should know, since I couldn't find anything on it when I was new to C++...

If I made any mistakes, please feel free to correct me.
If you set aside small char array, you can toss input in chunks using .sgetn() member function of streambuf.

This is good when you really need to clean the buffer, but it is rarely need to clear whole buffer.
Where it probably should not be used:
● To solve >> → getline problem (might still be used with modification: skip whitespaces until buffer is clear or newline is found)
● To discard errorneous input: if terminal input is expected, you need to skip over current input (sometimes not even whole line), if file input is expected, you usually want to discard current "block" which often means discard already read data.
[b]MiiNiPaa said[/b]:
To solve >> → getline problem


For that there is getline().
For that there is getline().
.ignore() or >> ws are better. They do not need string to write to, and describe youre intentions more clearly.

However direct stream manipulation is needed in case if you:
● Are not sure about previous stream operations.
● Want user to be able to input whitespaces at the beginning of the line.
It suddenly dawns me that there is readsome() member function in istream.

Now here is an example why clearing whole buffer might be bad idea: http://ideone.com/Jpp5H8
@MiiNiPaa

.ignore() or >> ws are better. They do not need string to write to, and describe youre intentions more clearly.


No they don't. cin.operator>>() does need a variable to write to, and cin.ignore() was not written for the purpose of clearing cin's buffer.

Now here is an example why clearing whole buffer might be bad idea


I don't think you understand: that's the whole point... If we want to get, say, 1 character that the USER enters, and he enters a crapload of nonsense, then we want to make sure that he's able to control the program... what you're saying would yield the program inoperable by the user until enough input operations have been invoked to clear the buffer.

I might agree with you, if I was talking about input from a file, but I'm not: I am taking about input specifically from the user.
Last edited on
I was answering to your answer to my point that it should not be used to deal with getline and stream extraction mixing problem. ignore is fine here and cin >> ws does not need any variable.

You are right with clearing buffer if user fails, but remember, even if you expect actual user input can be given by another program.

There is some other corner cases where clearing buffer is not needed, but many want to do that: for example when inputting sentiel terminated integer array where sentiel is anything non-integer.
I will enter "1 2 3 4 x 2 3 x x" in one line and then press enter. If it accepts only first array: you did not pass.

Also I must note, that input is not always line buffered and some of the user input can still sit in OS buffer, but I do not think that you will see that behavior in any mainstream OS.


Do not get me wrong, I am not trying to say that you should not clear input buffer or discrediting your idea. I just trying to point that you should know what happening under the hood and think if this is really needed.

OP is playing on Windows, which is why it worked. There is no standard way to toss all input, and the standard stream functions are not required to do anything but return 0. But the issue brings up a more insidious problem: incorrect thinking about how to process user input.

In a streams application you should never assume a human must be present to interact with it. There is never* a need to clear all input.

In a human-required interactive application (like a text editor or a game), there is still never a need to clear all input. (It should be processed as received, which may include skipping some inputs.)

*yes, never. I suppose it might be possible some highly-specialized application might some day exist, or may already exist in some obscure context on some ancient or primitive piece of hardware.


Learn to write your programs to keep themselves synchronized with input. These is a subject in itself. Unfortunately it is never taught as such; people are just expected to absorb it as they learn. Unfortunately, many never do, and we keep hearing about new issues due to input all the time. Randall was poking fun at that very problem with his "Little Bobby Tables" comic.
I learned today that usually, the standard input and output streams for the C++ and C I/O functions are synced

Didn't it happen in april?

http://www.cplusplus.com/forum/beginner/129450/
@Cubbi: he learned and forgot the first time, just like what happened to me. JLBorges had to tell me twice. It's some sort of curse.
Duoas said:
OP is playing on Windows, which is why it worked.

Correction: I'm using Linux Mint.
I think you shouldn't make such wild assumtions.

Cubbi said:
Didn't it happen in april?

How does that post translate to "cin.sync_with_stdio(false) is your answer"? Nowhere did it say that.

MiiNiPaa said:
I will enter "1 2 3 4 x 2 3 x x" in one line and then press enter. If it accepts only first array: you did not pass.


Actually, that does pass. I wouldn't clear the buffer. In this case, the user would actually be able to use cin.rdbuf()->in_avail() to accomplish this task, since cin isn't synced anymore.
Last edited on
Hate to jump in when I don't really have anything to contribute to the thread but IWishIKnew there isn't really a need to get defensive it's just a discussion.

Also

IWishIKnew wrote:
How does that post translate to "cin.sync_with_stdio(false) is your answer"? Nowhere did it say that.


From http://www.cplusplus.com/forum/beginner/129450/
Cubbi wrote:


Now if you unsynchronize them, in_avail (and therefore readsome) begins working where the library implementors cared enough to make it work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>

int main()
{
    std::cin.sync_with_stdio(false);

    std::cout << "Enter an integer followed by some garbage, please\n";
    int n;
    std::cin >> n;

    std::cin.ignore(std::cin.rdbuf()->in_avail());

    std::cout << "Now enter something else\n";
    std::string line;
    std::getline(std::cin, line);
    std::cout << "line = '" << line << "'\n";
}
Last edited on
I suppose I shouldn't be surprised that it works on some flavor of Linux, but it is not a "wild assumption". The behavior you are asking about is typical only on Windows with the Microsoft compiler.

You are right I should have not made the assumption.

Enjoy.
Topic archived. No new replies allowed.