C++ / CONSOLE AND FILE INPUT-OUTPUT
Reading input with cin and validating failure
Detect and recover from failed cin extractions by checking the stream's state bits, clearing failbit, and discarding the characters that caused the failure.
What you will learn
- Test the extraction itself with if (std::cin >> x), not the value it wrote
- Recover in the right order: std::cin.clear() first, then std::cin.ignore(...)
- Tell failbit from eofbit so a retry loop stops instead of spinning forever
- Detect trailing junk after a successful read with std::cin.peek()
Understanding Reading input with cin and validating failure
std::cin >> value is a parser, not a byte copier: it skips leading whitespace, then tries to match text that fits the grammar of value's type, and it returns the stream rather than the value. The stream converts to bool through an explicit conversion that reports !fail(), which is why if (std::cin >> n) reads as "did that parse work". Behind that interface a stream holds two separate things: a state made of failbit, eofbit and badbit (all clear means goodbit), and a queue of characters that have arrived but not yet been consumed.
When the text does not match, extraction stops before the offending character, sets failbit, and since C++11 stores 0 in the target, so the variable looks like ordinary data. A number that parses but does not fit the type also sets failbit, with the value clamped to that type's maximum or minimum. The consequence that bites people is that failbit is sticky: every stream operation starts by constructing a sentry that gives up when the state is not good, so once failbit is set, further >>, ignore and get calls do nothing at all. That turns an unchecked read loop into an infinite loop instead of merely a wrong answer.
Recovery must repair both halves of the damage, in order: clear() puts the state back to goodbit so operations work again, then ignore(std::numeric_limits<std::streamsize>::max(), '\n') throws away everything through the newline so the same characters cannot fail a second time. Before retrying, ask why the read failed: failbit together with eofbit means the input is finished and looping will never produce a number, while badbit means the stream itself broke and clearing is pointless. Separating those three cases is the difference between a program that politely asks again and one that hangs.
<iostream>
<limits>
int main() {
int age = 0;
// input fed to the program: a line "twelve", then a line "7"
while (!(std::cin >> age)) {
if (std::cin.eof()) { // nothing left to re-read
std::cout << "Input ended before a number arrived.\n";
return 1;
}
std::cin.clear(); // failbit -> goodbit
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Not a whole number, try again.\n";
}
std::cout << "age = " << age << '\n';
}
A failed cin >> x breaks two things at once, the stream's state bits and the unread characters still queued, and both must be repaired, state first, before any later read can succeed.
Worked examples
What a failed extraction leaves behind
Shows the state bits after a bad parse and proves the offending characters are still waiting in the buffer.
<iostream>
<string>
int main() {
int n = 999;
std::cin >> n; // the input line is: x42
std::cout << std::boolalpha
<< "n = " << n << '\n'
<< "fail = " << std::cin.fail() << '\n'
<< "eof = " << std::cin.eof() << '\n'
<< "bad = " << std::cin.bad() << '\n';
std::cin.clear(); // state bits only; the buffer is untouched
std::string rest;
std::cin >> rest;
std::cout << "still unread: " << rest << '\n';
}
Example explained
Line 1std::cin >> n matches nothing at 'x', so it fails and stores 0 in n, wiping the 999 that was there.
Line 2fail() is true while bad() is false: the parse mismatched, but the stream itself is perfectly healthy.
Line 3eof() is false because the characters were never consumed; extraction stopped in front of them.
Line 4clear() touches only the state, which is why the next read hands back the very text that failed: x42.
Out-of-range numbers fail too
Demonstrates that a well-formed number too large for the target type sets failbit and clamps the value.
<iostream>
<limits>
int main() {
short small = 12;
std::cin >> small; // the input line is: 40000
std::cout << std::boolalpha
<< "fail = " << std::cin.fail() << '\n'
<< "small = " << small << '\n'
<< "limit = " << std::numeric_limits<short>::max() << '\n';
}
Example explained
Line 140000 is a valid integer literal, so the digits parse; the failure comes from the range check against short.
Line 2The value is not left untouched: it saturates to numeric_limits<short>::max(), so 32767 looks like a real answer.
Line 3Testing if (std::cin >> small) is the only way to notice, since nothing about 32767 signals an error.
Line 4Here the digits were consumed, so a retry needs clear() and only the trailing newline to skip.
A successful read can still leave junk
Shows that >> stopping early is not a failure, and how to notice the characters it refused to read.
<iostream>
int main() {
int n = 0;
if (std::cin >> n) { // the input line is: 12abc
std::cout << "n = " << n << " (extraction succeeded)\n";
if (std::cin.peek() != '\n') {
std::cout << "left in the buffer: ";
char c;
while (std::cin.get(c) && c != '\n') std::cout << c;
std::cout << '\n';
}
}
}
Example explained
Line 1>> takes the longest valid integer, 12, then stops at 'a'; stopping early is success, not failure.
Line 2peek() reports the next character without consuming it, so it reveals the 'a' that is still queued.
Line 3get(c) returns the stream, so the loop ends at the newline or if the stream runs out of characters.
Line 4If your input format forbids trailing text, this check is what turns 12abc into a rejected line.
Important notes
clear() assigns a whole new state, it does not remove a bit: cin.clear(std::ios::failbit) sets failbit, and the no-argument form is the one that means "good again".
A read can succeed and set eofbit at the same time, for instance on a last line with no newline; if (std::cin >> x) still counts that as success because the bool conversion tests fail(), not eof().
Common mistakes
Calling ignore() before clear(): while failbit is set every stream operation is a no-op, so the bad text is never removed and the retry loop prints its error message forever.
Using cin.ignore() or cin.ignore(1) to "skip the bad character": the rest of the garbage line survives and fails the next extraction, so one typo produces a burst of error messages.
Using the variable without checking the stream: int n; std::cin >> n; on abc leaves n at 0 in C++11 and later, so the program silently computes with zero instead of reporting bad input.
Try it yourself
Change, predict, then run
Write a loop that keeps reading until it gets an int between 1 and 100, and feed it the lines abc, 250, then 42. Make sure the non-numeric line is recovered with clear() plus ignore(), while the out-of-range line is rejected without touching the stream state at all.
Open the C++ workspaceCheck your understanding
A retry loop is written as while (!(std::cin >> n)) { std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.clear(); } and the user types abc. What happens?
- It behaves like the usual order, because clear() and ignore() are interchangeable
- It stores 0 in n and leaves the loop after one iteration, because clear() makes the read succeed
- It loops forever, because ignore() does nothing while failbit is still set
- It discards one character per iteration, so it recovers after three iterations
Show answer
Every stream operation begins by constructing a sentry that gives up immediately when the state is not good, so ignore() consumes nothing while failbit is set; clear() then restores goodbit, but abc is still queued and the next >> fails on the same 'a'. Option 0 is tempting because both calls do execute, but in that order only clear() has any effect, and clear() never touches the character buffer.