Search code examples
c++error-handlingistream

C++ - Standard Input Loop


Stroustrup's Programming Principles and Practice Using C++ (2e, ch 10, print 6) gives the following idiom -- modified slightly to make it stand-alone and compilable -- for iteratively reading from an input stream until either EOF or a designated terminator character is encountered, with an exception thrown for any other stopping condition.

#include <iostream>
#include <stdexcept>

int main()
{
    std::istream& is = std::cin;
    char term = '|';  // terminator

    for (int x; is >> x; ) {
        // do something with x
    }
    if (is.bad()) {
        throw std::runtime_error("bad input stream");
    }
    if (is.fail()) {
        is.clear();
        char c;
        if (!(is >> c && c == term)) {
            throw std::runtime_error("bad termination of input");
        }
    }
    // carry on: we found EOF or terminator
}

The program comments and surrounding exposition imply that EOF is an acceptable (non-error-causing) way for this iterative read to end. But when I test this on files such as the following two-line text file containing no terminators,

3 1 4 1 5
9 2 6 5 3

an exception is thrown ("bad termination of input"). An exception is what I would expect -- after reading the final '3', the subsequent read encounters EOF, causing the stream's eofbit to be flipped, but the read also failed, causing the failbit to be flipped. The idiom seems to assume that eofbit and failbit are mutually exclusive.

Is this idiom serviceable or does it have a logical error in how the EOF case is handled?


Solution

  • According to this state reference the failbit is

    input/output operation failed (formatting or extraction error)

    The reference also says failbit is set

    if either eofbit or badbit is already set on the stream, or if the end of stream is encountered while consuming leading whitespace

    So encountering the end of the input itself doesn't set failbit, but attempting to read again will set failbit.