So that’s how you can use exceptions for input. But should you use them? It depends on the context. For this example, the answer is no. An exception should catch an unusual, unexpected occurrence, but this particular program uses a type mismatch as the intended way to exit the loop. It might make sense, however, for this program to throw an exception for badbit because that circumstance would be unexpected. Or if the program were designed to read numbers from a data file up to end-of-file, it might make sense to throw an exception for failbit because that would represent a problem with the data file.
Stream State Effects
An if or while test such as the following tests as true only if the stream state is good (all bits cleared):
while (cin >> input)
If a test fails, you can use the member functions in Table 17.4 to discriminate among possible causes. For example, you could modify the central part of Listing 17.11 to look like this:
while (cin >> input)
{
sum += input;
}
if (cin.eof())
cout << "Loop terminated because EOF encountered\n";
Setting a stream state bit has a very important consequence: The stream is closed for further input or output until the bit is cleared. For example, the following code won’t work:
while (cin >> input)
{
sum += input;
}
cout << "Last value entered = " << input << endl;
cout << "Sum = " << sum << endl;
cout << "Now enter a new number: ";
cin >> input; // won't work
If you want a program to read further input after a stream state bit has been set, you have to reset the stream state to good. This can be done by calling the clear() method:
while (cin >> input)
{
sum += input;
}
cout << "Last value entered = " << input << endl;
cout << "Sum = " << sum << endl;
cout << "Now enter a new number: ";
cin.clear(); // reset stream state
while (!isspace(cin.get()))
continue; // get rid of bad input
cin >> input; // will work now
Note that it is not enough to reset the stream state. The mismatched input that terminated the input loop is still in the input queue, and the program has to get past it. One way is to keep reading characters until reaching white space. The isspace() function (see Chapter 6, “Branching Statements and Logical Operators”) is a cctype function that returns true if its argument is a white-space character. Or you can discard the rest of the line instead of just the next word:
while (cin.get() != '\n')
continue; // get rid rest of line
This example assumes that the loop terminated because of inappropriate input. Suppose, instead, that the loop terminated because of end-of-file or because of a hardware failure. Then the new code disposing of bad input makes no sense. You can fix matters by using the fail() method to test whether the assumption was correct. Because for historical reasons, fail() returns true if either failbit or eofbit is set, the code has to exclude the latter case. The following code shows an example of such exclusion:
while (cin >> input)
{
sum += input;
}
cout << "Last value entered = " << input << endl;
cout << "Sum = " << sum << endl;
if (cin.fail() && !cin.eof() ) // failed because of mismatched input
{
cin.clear(); // reset stream state
while (!isspace(cin.get()))
continue; // get rid of bad input
}
else // else bail out
{
cout << "I cannot go on!\n";
exit(1);
}
cout << "Now enter a new number: ";
cin >> input; // will work now
Other istream Class Methods
Chapters 3 through 5 discuss the get() and getline() methods. As you may recall, they provide the following additional input capabilities:
• The get(char &) and get(void) methods provide single-character input that doesn’t skip over white space.
• The get(char *, int, char) and getline(char *, int, char) functions by default read entire lines rather than single words.
These are termed
Let’s look at these two groups of istream class member functions.
Single-Character Input
When used with a char argument or no argument at all, the get() methods fetch the next input character, even if it is a space, tab, or newline character. The get(char & ch) version assigns the input character to its argument, and the get(void) version uses the input character, converted to an integer type (typically int), as its return value.
The get(char &) Member Function
Let’s try get(char &) first. Suppose you have the following loop in a program:
int ct = 0;
char ch;
cin.get(ch);
while (ch != '\n')
{
cout << ch;
ct++;
cin.get(ch);
}
cout << ct << endl;
Next, suppose you type the following optimistic input:
I C++ clearly.