Why is this file stream, without error flags set, not readable unless I say tellg ()?

I have fstream that seems to fall into phantom's failure state, although checking it (by converting to bool ) does not display error flags. Subsequent reads do not work, which is unexpected.

 #include <fstream> #include <iostream> #include <cassert> int main() { const unsigned int SAMPLE_COUNT = 2; // Setup - create file with two "samples"; each sample has a double and a float { std::ofstream ofs("/tmp/ffs", std::ios::binary); const double colA[SAMPLE_COUNT] = { 1.0, 2.0 }; const float colB[SAMPLE_COUNT] = { 42.0, 100.0 }; for (size_t i = 0; i < SAMPLE_COUNT; i++) { ofs.write((char*)&colA[i], sizeof(colA[i])); ofs.write((char*)&colB[i], sizeof(colB[i])); } } // Actual testcase { std::fstream fs("/tmp/ffs", std::ios::binary | std::ios::out | std::ios::in); assert(fs); unsigned int sample_n = 0; while (true) { double a; fs.read((char*)&a, sizeof(a)); if (!fs) { std::cerr << "No more samples\n"; break; } std::cerr << "Sample " << (++sample_n) << " first column = " << a << '\n'; // Read column B float b; fs.read((char*)&b, sizeof(b)); assert(fs); std::cerr << "Current value second column = " << b << '\n'; // Multiply it by two and write back b *= 2; fs.seekp(-sizeof(b), std::ios::cur); fs.write((char*)&b, sizeof(b)); assert(fs); #ifdef DO_THE_TELLG // Unless I do this, the `fs.read` on the next iteration fails! // So the loop ends, and I get only the first sample transformed in my file. fs.tellg(); #endif } } // Inspection - should see values 84 and 200, but see 84 and 100 instead. { std::ifstream ifs("/tmp/ffs", std::ios::binary); std::cerr << "All values at end:\n"; for (size_t i = 0; i < SAMPLE_COUNT; i++) { double a; float b; ifs.read((char*)&a, sizeof(a)); ifs.read((char*)&b, sizeof(b)); std::cerr << a << '\t' << b << '\n'; } assert(ifs); } } 

Pay attention to the following conclusion: only the first sample was "parsed", and therefore at the end of the second sample retains its original value of 100 :

 [ root@localhost ~]# ./test Sample 1 first column = 1 Current value second column = 42 No more samples All values at end: 1 84 2 100 

If I perform a tellg() or tellp() operation on it, the subsequent read completes successfully, so the loop is not premature, and the second pattern is also multiplied by 2 to create 200 :

 [ root@localhost ~]# ./test Sample 1 first column = 1 Current value second column = 42 Sample 2 first column = 2 Current value second column = 100 No more samples All values at end: 1 84 2 200 

This only happens to me in the following environment:

  • CentOS 6 x86_64, GCC 4.4.7
  • CentOS 6 x86_64, GCC 4.8.2 (via devtoolset-2)

I get the expected behavior with or without tellg() / tellp() , on:

(Where the listed compiler supports both C ++ 03 and C ++ 11, I tried this under both and did not notice any difference.)

Does my program have UB? Or is it a libstdc ++ error that I need to work with?


Update: OK, so this is a known thing . But Ditmar does not say whether this is standard, or the libstdc ++ error. For me it looks like error 40732 , but it was RESOLVED / WONTFIX , so why does my program work as expected in Coliru and CentOS 7? Ideally, I would like to better understand what is going on before putting this solution in place.

0
source share

Source: https://habr.com/ru/post/1435681/


All Articles