This code loops forever:
#include <iostream>
#include <fstream>
#include <sstream>
int main(int argc, char *argv[])
{
std::ifstream f(argv[1]);
std::ostringstream ostr;
while(f && !f.eof())
{
char b[5000];
std::size_t read = f.readsome(b, sizeof b);
std::cerr << "Read: " << read << " bytes" << std::endl;
ostr.write(b, read);
}
}
It's because readsome
is never setting eofbit
.
cplusplus.com says:
Errors are signaled by modifying the internal state flags:
eofbit
The get pointer is at the end of the stream buffer's internal input array when the function is called, meaning that there are no positions to be read in the internal buffer (which may or not be the end of the input sequence). This happens whenrdbuf()->in_avail()
would return-1
before the first character is extracted.
failbit
The stream was at the end of the source of characters before the function was called.
badbit
An error other than the above happened.
Almost the same, the standard says:
[C++11: 27.7.2.3]:
streamsize readsome(char_type* s, streamsize n);
32. Effects: Behaves as an unformatted input function (as described in 27.7.2.3, paragraph 1). After constructing a sentry object, if
!good()
callssetstate(failbit)
which may throw an exception, and return. Otherwise extracts characters and stores them into successive locations of an array whose first element is designated bys
. Ifrdbuf()->in_avail() == -1
, callssetstate(eofbit)
(which may throwios_base::failure
(27.5.5.4)), and extracts no characters;
- If
rdbuf()->in_avail() == 0
, extracts no characters- If
rdbuf()->in_avail() > 0
, extractsmin(rdbuf()->in_avail(),n))
.33. Returns: The number of characters extracted.
That the in_avail() == 0
condition is a no-op implies that ifstream::readsome
itself is a no-op if the stream buffer is empty, but the in_avail() == -1
condition implies that it will set eofbit
when some other operation has led to in_avail() == -1
.
This seems like an inconsistency, even despite the "some" nature of readsome
.
So what are the semantics of readsome
and eof
? Have I interpreted them correctly? Are they an example of poor design in the streams library?
(Stolen from the [IMO] invalid libstdc++ bug 52169.)