Section 8.2. Condition States


8.2. Condition States

Before we explore the types defined in fstream and sstream, we need to understand a bit more about how the IO library manages its buffers and the state of a stream. Keep in mind that the material we cover in this section and the next applies equally to plain streams, file streams, or string streams.

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 library manages a set of condition state members that indicate whether a given IO object is in a usable state or has encountered a particular kind of error. The library also defines a set of functions and flags, listed in Table 8.2, that give us access to and let us manipulate the state of each stream.

Table 8.2. IO Library Condition State

strm::iostate

Name of the machine-dependent integral type, defined by each iostream class that is used to define the condition states.

strm::badbit

strm::iostate value used to indicate that a stream is corrupted.

strm::failbit

strm::iostate value used to indicate that an IO operation failed.

strm::eofbit

strm::iostate value used to indicate the a stream hit end-of-file.

s.eof()

true if eofbit in the stream s is set.

s.fail()

true if failbit in the stream s is set.

s.bad()

TRue if badbit in the stream s is set.

s.good()

true if the stream s is in a valid state.

s.clear()

Reset all condition values in the stream s to valid state.

s.clear(flag)

Set specified condition state(s) in s to valid. Type of flag is strm::iostate.

s.setstate(flag)

Add specified condition to s. Type of flag is strm::iostate.

s.rdstate()

Returns current condition of s as an strm::iostate value.


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

      int ival;      cin >> ival; 

If we enter Borges on the standard input, then cin will be put in an error state following the unsuccessful attempt to read a string of characters as an int. Similarly, cin will be in an error state if we enter an end-of-file. Had we entered 1024, then the read would be successful and cin would be in a good, non-error state.

To be used for input or output, a stream must be in a non-error state. The easiest way to test whether a stream is okay is to test its truth value:

           if (cin)                // ok to use cin, it is in a valid state           while (cin >> word)                // ok: read operation successful ... 

The if directly tests the state of the stream. The while does so indirectly by testing the stream returned from the expression in the condition. If that input operation succeeds, then the condition tests true.

Condition States

Many programs need only know whether a stream is valid. Other programs need more fine-grained access to and control of the state of the stream. Rather than knowing that the stream is in an error state, we might want to know what kind of error was encountered. For example, we might want to distinguish between reaching end-of-file and encountering an error on the IO device.

Each stream object contains a condition state member that is managed through the setstate and clear operations. This state member has type iostate, which is a machine-dependent integral type defined by each iostream class. It is used as a collection of bits, much the way we used the int_quiz1 variable to represent test scores in the example in Section 5.3.1 (p. 156).

Each IO class also defines three const values of type iostate that represent particular bit patterns. These const values are used to indicate particular kinds of IO conditions. They can be used with the bitwise operators (Section 5.3, p. 154) 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 continue using a stream after such an error. The failbit is set after a recoverable error, such as reading a character when numeric data was expected. It is often possible to correct the problem that caused the failbit to be set. The eofbit is set when an end-of-file is encountered. Hitting end-of-file also sets the failbit.

The state of the stream is revealed by the bad, fail, eof, and good operations. If any of bad, fail, or eof are true, then testing the stream itself will indicate that the stream is in an error state. Similarly, the good operation returns TRue if none of the other conditions is true.

The clear and setstate operations change the state of the condition member. The clear operations put the condition back in its valid state. They are called after we have remedied whatever problem occurred and we want to reset the stream to its valid state. The setstate operation turns on the specified condition to indicate that a problem occurred. setstate leaves the existing state variables unchanged except that it adds the additional indicated state(s).

Interrogating and Controlling the State of a Stream

We might manage an input operation as follows:

     int ival;     // read cin and test only for EOF; loop is executed even if there are other IO failures     while (cin >> ival, !cin.eof()) {         if (cin.bad())         // input stream is corrupted; bail out             throw runtime_error("IO stream corrupted");         if (cin.fail()) {                        // bad input             cerr<< "bad data, try again";        // warn the user             cin.clear(istream::failbit);         // reset the stream             continue;                            // get next input         }         // ok to process ival     } 

This loop reads cin until end-of-file or an unrecoverable read error occurs. The condition uses a comma operator (Section 5.9, p. 168). Recall that the comma operator executes by evaluating each operand and returns its rightmost operand as its result. The condition, therefore, reads cin and ignores its result. The result of the condition is the result of !cin.eof(). If cin hit end-of-file, the condition is false and we fall out of the loop. If cin did not hit end-of-file, we enter the loop, regardless of any other error the read might have encountered.

Inside the loop, we first check whether the stream is corrupted. If so, we exit by throwing an exception (Section 6.13, p. 215). If the input was invalid, we print a warning, and clear the failbit state. In this case, we execute a continue (Section 6.11, p. 214) to return to the start of the while to read another value into ival. If there were no errors, the rest of the loop can safely use ival.

Accessing the Condition State

The rdstate member function returns an iostate value that corresponds to the entire current condition state of the stream:

      // remember current state of cin      istream::iostate old_state = cin.rdstate();      cin.clear();      process_input();  // use cin      cin.clear(old_state); // now reset cin to old state 

Dealing with Multiple States

Often we need to set or clear multiple state bits. We could do so by making multiple calls to the setstate or clear functions. Alternatively, we could use the bitwise OR (Section 5.3, p. 154) operator to generate a value to pass two or more state bits in a single call. The bitwise OR generates an integral value using the bit patterns of its operands. For each bit in the result, the bit is 1 if the corresponding bit is 1 in either of its operands. For example:

    // sets both the badbit and the failbit    is.setstate(ifstream::badbit | ifstream::failbit); 

tells the object is to turn on both the failbit and the badbit. The argument

      is.badbit | is.failbit 

creates a value in which the bits corresponding to the badbit and to the failbit are both turned onthat is they are both set to 1. All other bits in the value are zero. The call to setstate uses this value to turn on the bits corresponding to badbit and failbit in the stream's condition state member.



C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net