19

In C, I can easily set a stream to unbuffered I/O:

FILE * f = fopen( "test", "r" );
setvbuf( f, (char *)NULL, _IONBF, 0 );

How would I achieve similarly unbuffered I/O using C++ IOStreams?

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • I think `fopen()` returns `FILE*` is hight level it do buffer management implicitly, whereas with low-level file handling using file descriptor `open()` you have to do buffer manipulation explicitly. – Grijesh Chauhan May 17 '13 at 09:10
  • 2
    @bjskishore123: This is not a C question, the C example was only for clarification what I was talking about. Reverted your tag edit. – DevSolar May 17 '13 at 09:19
  • @GrijeshChauhan: No. `fopen()` is ISO C, `open()` is POSIX, and the implicit buffering of the ISO C functions can be disabled as I demonstrated. Anyway this is completely beside the question (which is "how to achieve unbuffered I/O *with C++ streams*"). – DevSolar May 17 '13 at 09:21
  • 1
    thanks!! I was unaware of how to disable implicit buffering. – Grijesh Chauhan May 17 '13 at 09:27
  • 1
    @GrijeshChauhan: Then be aware that you **must not** call `setvbuf()` after you have done *anything else* with the `FILE` in question (other than `fopen()`, of course). That would be UB. – DevSolar May 17 '13 at 09:50
  • Thanks DevSolar for this useful information, I appreciate it and find interesting, I will read further about it Thanks :) – Grijesh Chauhan May 17 '13 at 11:56

1 Answers1

31

For file streams, you can use pubsetbuf for that :

std::ifstream f;
f.rdbuf()->pubsetbuf(0, 0);
f.open("test");


Explanation

The C++ standard says the following about the effect of setbuf (and thus pubsetbuf) for file streams :

If setbuf(0,0) is called on a stream before any I/O has occurred on that stream, the stream becomes unbuffered. Otherwise the results are implementation-defined. “Unbuffered” means that pbase() and pptr() always return null and output to the file should appear as soon as possible.

The first sentence guarantees that the above code makes the stream unbuffered. Note that some compilers (eg. gcc) see opening a file as an I/O operation on the stream, so pubsetbuf should be called before opening the file (as above).

The last sentence, however, seems to imply that that would only be for output, and not for input. I'm not sure if that was an oversight, or whether that was intended. Consulting your compiler documentation might be useful. For gcc eg., both input and output are made unbuffered (ref. GNU C++ Library Manual - Stream Buffers).

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • 2
    Nitpicking: `putsetbuf` calls [`setbuf`](http://en.cppreference.com/w/cpp/io/basic_filebuf/setbuf) which exact behaviour is implementation dependant. According to the linked doc, some compilers (namely GCC) require that it is called *before* opening the file. +1 anyway for finding this. :) – syam May 17 '13 at 09:25
  • 2
    ...and in any case, before any actual I/O took place. I took the liberty of making the answer "GCC-safe". Thanks for this find! – DevSolar May 17 '13 at 09:29
  • 2
    @syam: the behavior of `setbuf(0,0)` isn't implementation defined; for other arguments it is. – Michael Burr May 17 '13 at 09:32
  • @MichaelBurr: I disagree. `setbuf(0,0)` is only required to disable buffering **if** called before any I/O, but there's no other requirement. A conforming implementation may choose to allow `setbuf(0,0)` to disable buffering even after I/O has taken place. (again, according to cppreference.com -- I don't have the heart to dig into the standard right now) – syam May 17 '13 at 09:40
  • @syam: I think what Michael was referring to is that behaviour of `setbuf(0,0)` isn't implementation-defined (it turns off buffering), just the constraints of where it might be called are. (And you might note that the `setvbuf()` I used as C example requires to be called prior to any actual I/O as well.) Anyways, if calling `setbuf(0,0)` before opening the file, you ought to be on the safe side. – DevSolar May 17 '13 at 09:46
  • @DevSolar: Ok I couldn't help it after all. **27.9.1.5-12** *If setbuf(0,0) is called on a stream before any I/O has occurred on that stream, the stream becomes unbuffered. Otherwise the results are implementation-defined.* To me the wording is quite clear: `setbuf(0,0)` is specified only if called before I/O. Anything else (after I/O and/or other arguments) is implementation-dependant, `setbuf(0,0)` isn't required to (but still may) turn off buffering if called after I/O. But yeah, I'm nitpicking again, obviously the safe thing is to call it before opening the file. ;) – syam May 17 '13 at 09:52
  • @DevSolar : I just noticed the standard implies that it's only unbuffered for output : *“Unbuffered” means that pbase() and pptr() always return null and output to the file should appear as soon as possible.* I'm not sure if that was an oversight, or whether that's indeed a difference between `setvbuf` in C (which disables buffering for both input and output) and `pubsetbuf` in C++. – Sander De Dycker May 17 '13 at 10:10
  • Isn't `std::ifstream` unbuffered by default? The [default constructor](https://en.cppreference.com/w/cpp/io/basic_filebuf/basic_filebuf) of `std::basic_filebuf` calls the [default constructor](https://en.cppreference.com/w/cpp/io/basic_streambuf/basic_streambuf) of `std::stream_buf`, which initializes the six pointer members (`eback()`, `gptr()`, `egptr()`, `pbase()`, `pptr()`, and `epptr()`) to null pointer values. – xskxzr Apr 17 '20 at 13:12
  • @xskxzr : that's because the default constructed `std::basic_filebuf` isn't associated with a file yet, so there's no need to have put or get areas defined already. Those are typically defined when [`std::basic_filebuf::open`](https://en.cppreference.com/w/cpp/io/basic_filebuf/open) is called, or possibly delayed even further until either [`std::basic_filebuf::overflow`](https://en.cppreference.com/w/cpp/io/basic_filebuf/overflow) or [`std::basic_filebuf::underflow`](https://en.cppreference.com/w/cpp/io/basic_filebuf/underflow) is called. The latter's example code and output illustrate this. – Sander De Dycker Apr 17 '20 at 22:23
  • @xskxzr : Note that that is also a reason for the restriction that `setbuf` needs to be called before I/O has happened (ie. before the put and get areas are defined). On some platforms, that needs to be done before opening the file, on others before doing a read or write, and yet others might allow changing the buffer even after I/O has happened. The notes for [`std::basic_filebuf::setbuf`](https://en.cppreference.com/w/cpp/io/basic_filebuf/setbuf) give examples of such platforms. – Sander De Dycker Apr 17 '20 at 22:30
  • @SanderDeDycker But none of the pages you linked mention the change of get/put area, am I missing something? – xskxzr Apr 18 '20 at 01:05
  • @xskxzr : The main page for [`std::basic_filebuf`](https://en.cppreference.com/w/cpp/io/basic_filebuf) mentions what controls the put and get areas eg. What you're missing though, is that the standard doesn't say that file streams *have* to be buffered (nor does it say the opposite) - it just adds some constraints (like the `setbuf(0,0)` constraint described in this answer). If you're unconvinced, I suggest experimenting with your favorite standard library (and/or delving in its source code) - you're more likely to find that file buffering *is* the default than not. – Sander De Dycker Apr 18 '20 at 06:35