Reputation: 35
The authors explain how to write a function which reads grades from standard input and puts them into a vector, but they do it in a confusing fashion. I'll put here an excerpt that confuses me:
... we don’t quite know when to stop. We can keep reading grades until we can no longer do so, but at that point we have a problem.
There are two reasons why we might no longer be able to read a grade:
We might have reached end-of-file, or we might have encountered something that is not a grade.In the first case, our caller will think that we have reached end-of-file. This thought will be true but misleading, because the end-of-file indication will have occurred only after we have successfully read all the data.
Normally, an end-of-file indication means that an input attempt failed.In the second case, when we have encountered something that isn’t a grade, the library will mark the input stream as being in failure state, which means that future input requests will fail, just as if we had reached end-of-file.
Therefore, our caller will think that something is wrong with the input data, when the only problem was that the last homework grade was followed by something that was not a homework grade.
In either case, then, we would like to pretend that we never saw whatever followed the last homework grade.
Such pretense turns out to be easy:
If we reached end-of-file, there was no additional input to read; if we encountered something that wasn’t a grade, the library will have left it unread for the next input attempt.Therefore, all we must do is tell the library to disregard whatever condition caused the input attempt to fail, be it end-of- file or invalid input.
We do so by callingin.clear()
to reset the error state insidein
, which tells the library that input can continue despite the failure.
I understand the part that tells that there are two reasons that make us unable to read data.
The first is the end-of-file, and the second is a piece of data that cannot be treated as a double.
And now, the authors try to go deeper into these two cases which confuses me. They say that we need to read all the data to get the end-of-file indication, and right after that, they say that any fail of getting input, leads to the end-of-file indication. It seems like the authors contradict themselves.
I put a bit more text here, so you have some context, and I need a more clear and understandable rewrite.
Upvotes: 1
Views: 134
Reputation: 48022
The authors tell that we need to read all the data to get the end-of-file indication and right after they tell that any fail of getting input leads to the end-of-file indication.
This sounds like a contradiction, but a failure does not actually lead to an end-of-file indication.
An input stream has several flags to keep track of its state. One
eofbit
is set if a read was been attempted after then end of the input (file) was reached.failbit
is set if an extraction failed because the data wasn't in the expected format.badbit
is set if there has been an unrecoverable error, e.g., if it wasn't able to open the file at all.(In the documentation, you may also see goodbit
, but the stream's state doesn't have a but for that. The state is good if the other three bits are all clear.)
Without the code snippet being described by the text, we don't know which method they authors are using to test the stream's state. There's a useful table at the bottom of this page that shows the possible combinations of the stream's state bits and the various ways to check them.
Depending on how it's written, a loop may terminate if there's a problem extracting a grade or if it has reached the end of the file. By calling the clear
method and attempting another read, it becomes possible to distinguish between the causes.
Upvotes: 1
Reputation: 51874
The point of confusion, here, is (most likely) with the phrase, "just as if we had reached end-of-file" (although, I agree, the whole paragraph is somewhat mumbly and meandering).
When using a std::ifstream
object (or one from a derived/related class), there are a number of conditions that can cause an attempted read operation to fail: one is that the end-of-file has been reached (in which case we're done); another is that bad input data – i.e. a character or characters that cannot be interpreted as a double
(say) – is encountered in the file stream.
In the latter case, the read will fail and a flag (typically the failbit
or badbit
members) will be set. In the former case, the eofbit
member will (also) be set.
We can call the .fail()
member function of the stream object to test if either of those situations has occurred, and we can call the .eof()
member function to test specifically if the end-of-file has been reached.
If fail()
returns true
but eof()
returns false
, then we can call the .clear()
function to reset/clear the flags, after which we can continue reading (or trying to read) more data. We can continue this read/test/clear cycle until we get an actual EOF.
Upvotes: 2