8.1.2. Condition States

Inherent in doing IO is the fact that errors can occur. Some errors are recoverable; others occur deep within the system and are beyond the scope of a program to correct. The IO classes define functions and flags, listed in Table 8.2, that let us access and manipulate the condition state of a stream.

Table 8.2. IO Library Condition State

Image

As an example of an IO error, consider the following code:

int ival;
cin >> ival;

If we enter Boo on the standard input, the read will fail. The input operator expected to read an int but got the character B instead. As a result, cin will be put in an error state. Similarly, cin will be in an error state if we enter an end-of-file.

Once an error has occurred, subsequent IO operations on that stream will fail. We can read from or write to a stream only when it is in a non-error state. Because a stream might be in an error state, code ordinarily should check whether a stream is okay before attempting to use it. The easiest way to determine the state of a stream object is to use that object as a condition:

while (cin >> word)
    // ok: read operation successful . . .

The while condition checks the state of the stream returned from the >> expression. If that input operation succeeds, the state remains valid and the condition will succeed.

Interrogating the State of a Stream

Using a stream as a condition tells us only whether the stream is valid. It does not tell us what happened. Sometimes we also need to know why the stream is invalid. For example, what we do after hitting end-of-file is likely to differ from what we’d do if we encounter an error on the IO device.

The IO library defines a machine-dependent integral type named iostate that it uses to convey information about the state of a stream. This type is used as a collection of bits, in the same way that we used the quiz1 variable in § 4.8 (p. 154). The IO classes define four constexpr values (§ 2.4.4, p. 65) of type iostate that represent particular bit patterns. These values are used to indicate particular kinds of IO conditions. They can be used with the bitwise operators (§ 4.8, p. 152) to test or set multiple flags in one operation.

The badbit indicates a system-level failure, such as an unrecoverable read or write error. It is usually not possible to use a stream once badbit has been set. The failbit is set after a recoverable error, such as reading a character when numeric data was expected. It is often possible to correct such problems and continue using the stream. Reaching end-of-file sets both eofbit and failbit. The goodbit, which is guaranteed to have the value 0, indicates no failures on the stream. If any of badbit, failbit, or eofbit are set, then a condition that evaluates that stream will fail.

The library also defines a set of functions to interrogate the state of these flags. The good operation returns true if none of the error bits is set. The bad, fail, and eof operations return true when the corresponding bit is on. In addition, fail returns true if bad is set. By implication, the right way to determine the overall state of a stream is to use either good or fail. Indeed, the code that is executed when we use a stream as a condition is equivalent to calling !fail(). The eof and bad operations reveal only whether those specific errors have occurred.

Managing the Condition State

The rdstate member returns an iostate value that corresponds to the current state of the stream. The setstate operation turns on the given condition bit(s) to indicate that a problem occurred. The clear member is overloaded (§ 6.4, p. 230): One version takes no arguments and a second version takes a single argument of type iostate.

The version of clear that takes no arguments turns off all the failure bits. After clear(), a call to good returns true. We might use these members as follows:

// remember the current state of cin
auto old_state = cin.rdstate();   // remember the current state of cin
cin.clear();                      // make cin valid
process_input(cin);               // use cin
cin.setstate(old_state);          // now reset cin to its old state

The version of clear that takes an argument expects an iostate value that represents the new state of the stream. To turn off a single condition, we use the rdstate member and the bitwise operators to produce the desired new state.

For example, the following turns off failbit and badbit but leaves eofbit untouched:

// turns off failbit and badbit but all other bits unchanged
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);


Exercises Section 8.1.2

Exercise 8.1: Write a function that takes and returns an istream&. The function should read the stream until it hits end-of-file. The function should print what it reads to the standard output. Reset the stream so that it is valid before returning the stream.

Exercise 8.2: Test your function by calling it, passing cin as an argument.

Exercise 8.3: What causes the following while to terminate?


while (cin >> i) /*  ...    */


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.227.82