Let’s take a closer look at what happens for inappropriate input. A cin or cout object contains a data member (inherited from the ios_base class) that describes the stream state. A stream state (defined as type iostate, which, in turn, is a bitmask type, such as described earlier) consists of the three ios_base elements: eofbit, badbit, and failbit. Each element is a single bit that can be 1 (set) or 0 (cleared). When a cin operation reaches the end of a file, it sets eofbit. When a cin operation fails to read the expected characters, as in the earlier example, it sets failbit. I/O failures, such as trying to read a non-accessible file or trying to write to a write-protected disk, also can set failbit to 1. The badbit element is set when some undiagnosed failure may have corrupted the stream. (Implementations don’t necessarily agree about which events set failbit and which set badbit.) When all three of these state bits are set to 0, everything is fine. Programs can check the stream state and use that information to decide what to do next. Table 17.4 lists these bits, along with some ios_base methods that report or alter the stream state.

Table 17.4. Stream States

Setting States

Two of the methods in Table 17.4, clear() and setstate(), are similar. Both reset the state, but they do so in a different fashion. The clear() method sets the state to its argument. Thus, the following call uses the default argument of 0, which clears all three state bits (eofbit, badbit, and failbit):

clear();

Similarly, the following call makes the state equal to eofbit; that is, eofbit is set, and the other two state bits are cleared:

clear(eofbit);

The setstate() method, however, affects only those bits that are set in its argument. Thus, the following call sets eofbit without affecting the other bits:

setstate(eofbit);

So if failbit was already set, it stays set.

Why would you reset the stream state? For a program writer, the most common reason is to use clear() with no argument to reopen input after encountering mismatched input or end-of-file; whether doing so makes sense depends on what the program is trying to accomplish. You’ll see some examples shortly. The main purpose for setstate() is to provide a means for input and output functions to change the state. For example, if num is an int, the following call can result in operator>>(int &) using setstate() to set failbit or eofbit:

cin >> num;  // read an int

I/O and Exceptions

Suppose that an input function sets eofbit. Does this cause an exception to be thrown? By default, the answer is no. However, you can use the exceptions() method to control how exceptions are handled.

First, here’s some background. The exceptions() method returns a bitfield with three bits corresponding to eofbit, failbit, and badbit. Changing the stream state involves either clear() or setstate(), which uses clear(). After changing the stream state, the clear() method compares the current stream state to the value returned by exceptions(). If a bit is set in the return value and the corresponding bit is set in the current state, clear() throws an ios_base::failure exception. This would happen, for example, if both values had badbit set. It follows that if exceptions() returns goodbit, no exceptions are thrown. The ios_base::failure exception class derives from the std::exception class and thus has a what() method.

The default setting for exceptions() is goodbit—that is, no exceptions thrown. However, the overloaded exceptions(iostate) function gives you control over the behavior:

cin.exceptions(badbit);  // setting badbit causes exception to be thrown

The bitwise OR operator (|), as discussed in Appendix E, allows you to specify more than one bit. For example, the following statement results in an exception being thrown if either badbit or eofbit is subsequently set:

cin.exceptions(badbit | eofbit);

Listing 17.12 modifies Listing 17.11 so that the program throws and catches an exception if failbit is set.

Listing 17.12. cinexcp.cpp

// cinexcp.cpp -- having cin throw an exception

#include

#include

int main()

{

    using namespace std;

    // have failbit cause an exception to be thrown

    cin.exceptions(ios_base::failbit);

    cout << "Enter numbers: ";

    int sum = 0;

    int input;

    try {

        while (cin >> input)

        {

            sum += input;

        }

    } catch(ios_base::failure & bf)

    {

        cout << bf.what() << endl;

        cout << "O! the horror!\n";

    }

    cout << "Last value entered = " << input << endl;

    cout << "Sum = " << sum << endl;

    return 0;

}

Here is a sample run of the program in Listing 17.12; the what() message depends on the implementation:

Enter numbers: 20 30 40 pi 6

ios_base failure in clear

O! the horror!

Last value entered = 40.00

Sum = 90.00

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги