AlwaysLearning
AlwaysLearning

Reputation: 8011

Is it OK to continue reading from stream after failure?

I am using the following loop to read numbers from two files until both are exhausted:

int a, b;
while (file1 >> a, file2 >> b, file1 || file2) {
    if (file1 && file2) ... // use of both a and b
    if (file1) ... // use of a
    if (file2) ... // use of b
}

My program works. But is it guaranteed to work by the standard? That is, am I permitted to continue reading from a failed stream or an implementation can choose to throw an exception?

Upvotes: 3

Views: 633

Answers (2)

Michael Kenzel
Michael Kenzel

Reputation: 15943

Short answer: Yes, you can attempt to input something from a stream as many times as you want. Even after an attempt to input something from that stream failed. All that will happen is that all attempts to input something after a failed attempt to input something will also fail.

Long answer: operator >> behaves as a formatted input function [istream.formatted.arithmetic]. Formatted input functions construct a local sentry object and only perform input if converting that sentry object to bool results in the value true [istream.formatted.reqmts]. By default (if you did not override this behavior by supplying custom character traits to the stream), an object of type std::sentry will be used. An std::sentry that has been constructed for a stream will evaluate to true only if good() was true [istream::sentry]. good() only returns true if neither failbit nor badbit nor eofbit are set [iostate.flags]/7. If operator >>(int&) attempts to input (due to successful construction and check of the sentry) but fails to do so, it will set the failbit [istream.formatted.arithmetic]/3. If the corresponding flag in the exception mask of the stream is set (it is not set by default), setting the failbit will result in an exception being thrown [iostate.flags]/6 [iostate.flags]/5. Otherwise, the stream will simply be in a failed state and construction of a sentry object will result in false the next time around until you call clear()

I would consider rewriting this code, for example

do
{
    if (int a; file1 >> a)
        ; // use a
    if (int b; file2 >> b)
        ; // use b
} while (file1 || file2);

Upvotes: 4

Nadav Har'El
Nadav Har'El

Reputation: 13731

Yes, you can do this. Once a stream is in a failed state (failbit), further reads will also fail, but this is what you wanted to happen. These reads will not throw an exception - the failbit will only generate an exception if this is explicitly enabled via the stream's exceptions() method. According to this source, the default is that these exceptions are not enabled:

All streams have goodbit by default (they do not throw exceptions due to error state flags being set).

Upvotes: 0

Related Questions