7

I have a function which works with a std::ostream. I need to support using a C file handle (FILE*). Should I be creating my own subclass of std::ostream which delegates to a FILE*?

Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
Akusete
  • 10,704
  • 7
  • 57
  • 73
  • If you want to go nuts and change it back, go ahead. Nothing about wrapping things with classes, or FILE* inherited and standardized separately from C makes it a C question. As Stackoverflow-ers love to point out, C is not a subset of C++. – Matt Joiner Nov 11 '10 at 12:59
  • See [this](http://ilab.usc.edu/rjpeters/groovx/classrutz_1_1stdiobuf.html) subclass of `streambuf` that wraps `FILE*`. – Keith Pinson Feb 20 '13 at 20:55
  • @Kazark: Awesome... If you post that as an answer I'd accept it :) – Akusete Feb 20 '13 at 21:51
  • Note that this is related to the question: http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor – Hugues May 06 '16 at 16:13

2 Answers2

8

As Ben Voigt points out, you want to subclass streambuf. There are pages on the University of Southern California's website which have the documentation, header, and source for a GNU implementation of a streambuf subclass (stdiobuf) that wraps a FILE*. It has some dependencies on the library it is a part of (GroovX), but those should be easily to remove (I would begin by removing all references to GVX_TRACE).

Interestingly, it also provides a minimalistic subclass (stdiostream) of std::iostream, in spite of what Ben Voigt said. But this does not seem to be necessary, as the rdbuf ("read buffer"/set the stream buffer) method which the stdiostream class uses to connect the stdiobuf class to a stream object is publicly accessible.

You can find more about subclassing streambuf here (look particularly at the bottom of the page, which discussing the virtual functions). The implementation linked above overrides sync, underflow (to support input) and overflow (to support output).

Further notes about the linked implementation:

  • The init method uses the setg and setp methods to set the pointers for the input and output sequences.
  • The line const int num = pptr()-pbase(); is calculating the number of characters to flush by subtracting the base output pointer from the current output pointer ("put pointer").
  • The variable unhelpfully named om is the mode parameter.
  • The variable named fd is the file descriptor.
Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
6

No, ostream is not meant to be derived from. The way the iostreams library allows customization is by supplying a streambuf pointer when creating an ostream. streambuf has a lot of virtual functions so you can change its behavior.

You need to derive either directly from streambuf or from the existing filebuf subclass. You probably only need to provide the overflow function, the defaults for all the others should work ok.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Wow that actually sounds halfway clean. – R.. GitHub STOP HELPING ICE Nov 11 '10 at 06:01
  • Well, iostreams is designed to be extensible. A week or so ago, I wrote one `stingbuf` to allow data written to `cout` to show up in a UI textbox when there was no console window attached (just overrode `sync`), and also an input `streambuf` subclass using memory-mapped files and which was in the neighborhood of 20-30 times faster than the `ifstream`+`getline`+`istringstream` I had been used for textfile processing. It's really amazing how inefficient the standard streambuf implementations are, because they try to fit every possible scenario. – Ben Voigt Nov 11 '10 at 06:53
  • 1
    Actually, it's perfectly OK to derive from `ostream`, see for instance `ofstream`. However, such derived classes just provide a convenenience ctor that calls `ostream::ostream(streambuf*)`. – MSalters Nov 11 '10 at 10:12