0

I had code like below. I feel like the file stream didn't reach the file end, because ln_cnt value isn't equal to the feature count (i.e. number of polyline features) shown in QGIS.

Such inequality happend when the shapefile is large so I can't count features one by one, but I used small-sized shapefile for test already and my code works well.

polyline_class line_1;

int ln_cnt ++; // the counter for counting the lines that's read

ifstream reader("some_polyline.shp", ios::in | ios::binary);

while (!reader.eof()){

    shp_read_pnt(&reader, &line_1);
    ln_cnt ++;

}

cout << ".good() = " << reader.good() << "\n";
cout << ".bad() = " << reader.bad()   << "\n";
cout << ".fail() = " << reader.fail() << "\n";
cout << ".eof() = " << reader.eof()   << "\n";
cerr <<  "Error: " << strerror(errno);
reader.close();

The result is :

.good() = 0
.bad() = 0
.fail() = 1
.eof() = 1
Error: No error

Is there an error, actually ?

Justin
  • 217
  • 1
  • 11
  • 1
    Probably unrelated (but hard to be sure): [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) – user4581301 Feb 26 '21 at 01:09
  • 2
    On topic, a great many things can happen in a stream that will not set `errno` and thus have no effect on `strerror`. In this case it certainly looks like the stream hit the end of the file. Not the sort of thing `errno` is concerned with. This is discussing C, but the end result will be similar: [Does EOF set errno?](https://stackoverflow.com/questions/22601893/does-eof-set-errno) – user4581301 Feb 26 '21 at 01:10
  • `ln_cnt` isn't even initialized in the code you posted. You should post a reproducible example if you want useful answers. – spectras Feb 26 '21 at 01:15
  • `int ln_cnt ++;` is not a valid expression. You need `int ln_cnt = 0;` instead – Remy Lebeau Feb 26 '21 at 01:31

2 Answers2

1

TL;DR 'good' is not the opposite of 'bad', 'good' is the opposite of 'fail'

iostreams have two1 persistent status bits that record the results of previous operations on the stream. Both bits are 'sticky' -- they start false, and are set to true when certain things happen, and then remain true until they are explicitly cleared via calling clear()

  • eof: set if a read couldn't get data to read due to reaching an end-of-file
  • bad: set if an error occurred on the underlying device

The eof() and bad() functions check these bits, and fail() checks both of them (so fail() == eof() || bad()). Now the confusing part -- good() checks both as well, so good IS NOT the opposite of bad. Instead good() == !fail().

That's pretty much it, and explains the results you are seeing. You read to an end of file, so the eof bit got set, but there was never any error, so bad remains clear. You have fail() == eof() || bad() and good() == !fail() exactly as one would expect.


1Ok, technically the above is wrong -- there are potentially more bits stored (including a good bit and a fail bit), but the overall behavior is as the above explains -- the fail bit will be set when either the bad or eof bit is set, and will only ever be set when one of them is. The good bit will always be cleared when the fail bit is set. The only way for things to become inconsistent with the above is if the user manually sets the bits to some odd combination with clear(some-odd-state), but its not clear why anyone would ever do that. The default state set by clear() has (just) the good bit set.

Chris Dodd
  • 101,438
  • 11
  • 111
  • 197
0

There's not really a safe way to tell, since you obviously did not post all the code (e. g. the implementation of shp_read_pnt() is missing), but I will try it anyway:

The read operations of std::ifstream are (in general) not required to set errno at all. Or in other words: It may be perfectly legal for one of the read operations of std::ifstream to fail and still not set errno at all.

C++ streams usually use exceptions or the various error bits (which can be queried with fail(), bad() etc.) to signal that something went wrong. So these should be used instead of errno.

Striezel
  • 3,274
  • 7
  • 19
  • 33