2

When using a std::fstream you can read and write to the file. I'm wondering if there is any part of the C++ standard stating the requirements for switching between read & write operations.

What I found is:

The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf<charT, traits> are the same as for reading and writing with the C standard library FILEs.
In particular:

— If the file is not open for reading the input sequence cannot be read.
— If the file is not open for writing the output sequence cannot be written.
— A joint file position is maintained for both the input sequence and the output sequence

So according to only the bullet points if I open a std::fstream, read 5 bytes, then write 2 bytes the new bytes will end up at position 6 & 7: First 2 conditions are met and due to the "joint file position" the read will advance the write position by 5 bytes.

However in practice intermediate buffers are used instead of directly calling fread/fwrite for every single byte. Hence the 5-byte-read could read 512 bytes from the underlying FILE and if that is not accounted for during the write that will end up at position 513 not 6 in the above example.

And indeed libstdc++ (GCC) does correct the offsets: https://github.com/gcc-mirror/gcc/blob/13ea4a6e830da1f245136601e636dec62e74d1a7/libstdc%2B%2B-v3/include/bits/fstream.tcc#L554

I haven't found anything similar in libc++ (Clang) or MS STL, although MS "cheats" by using the buffers from the FILE* inside the filebuf, so it might "work" there.

Anyway: For the C functions I found that switching between read & write requires a seek or flush (after write): https://en.cppreference.com/w/c/io/fopen

So does the part "The restrictions [...] of class basic_filebuf<charT, traits> are the same as [...] with the C standard library" may also be applied to this, so a seekg, seekp, tellg, tellp or sync is required to switch between operations?

Context: I maintain a library providing an (enhanced) filebuf class and not checking if the FILE* position needs to be adjusted to account for buffering due to potential read/write switches without seek/sync saves a potentially expensive conditional. But I don't want to deviate from the standard requirements to not break users expecting a drop-in replacement.

Flamefire
  • 5,313
  • 3
  • 35
  • 70
  • In relation to your "intermediate buffers", I would think that those are flushed/cleared/reset when the operation mode switches from read to write (or v/v) and any file pointers are, at that time, set to their *actual* positions. How that is done will be implementation-defined. – Adrian Mole Jun 13 '22 at 10:38
  • Yes, those buffers are more or less an implementation detail and yes they need to be reset when switching modes. Question is if an implementation is required to detect that automatically, or if it can assume an explicit seek/sync from the user where a flush/reset is due anyway and hence a check in the read/write part is not required – Flamefire Jun 13 '22 at 10:47
  • OK. [This answer](https://stackoverflow.com/a/17567454/10871073) suggests (very strongly) that it is GCC that is not following the C++ Standard, by not inheriting the C Standard's restrictions. – Adrian Mole Jun 13 '22 at 11:12
  • ... and the **C++** Standard you cite does *categorically* state that the restrictions are the same as for the equivalent C operations. So, without any other statement of exceptions, then the requirement for **explicit** calls to the relevant "seek", "flush" or "sync" function would stand. – Adrian Mole Jun 13 '22 at 11:21
  • AFAIK the C++ standard doesn't explicitly list the requirement of a seek while it does list the "joint position". So one could argue that it is rather (solely) GCC following the standard as (only) there one cannot observe different read and write positions. And even if the C++ standard is meant to require a seek then not doing a seek between read&write would be UB and GCC is allowed to not require a seek in that case while still following the standard. – Flamefire Jun 13 '22 at 12:39

0 Answers0