Is it okay to initialize a std::iostream with a NULL streambuf?

64 views Asked by At

I'd like to use std::iostream with file descriptors. Unfortunately, since there's no portable way to get file descriptors other than 0-2 into or (at least until C++26) out of an fstream, I had to implement my own streambuf type, which I called fdstreambuf. I would now like to implement an fdstream like this:

struct fdstream : public std::iostream {
  fdstreambuf buf_;
  fdstream(int fd) : buf_(fd) { rdbuf(&buf_); }
};

Unfortunately, this doesn't work, because std::iostream doesn't have a default constructor. When I look at how gcc's libstdc++ implements things like ostringstream, it uses a default constructor for ostream that uses 0 for the streambuf*, even though such a constructor is not part of the C++ specification. I can do the same for an iostream by passing in nullptr for the streambuf initially. (Since buf_ won't be initialized before the supertype, I don't want to initialize the supertype with &buf_.) So right now this seems to work:

  fdstream(int fd) : std::iostream(nullptr), buf_(fd) { rdbuf(&buf_); }

My question: is the above code legal? And if not, how are you supposed to define an iostream type that includes its own streambuf type as a structure field?

I guess another question would be am I missing some other way to access file descriptors? It seems very unfortunate that the C++ spec requires the standard library to provide streambufs that work with file descriptors, since cin, cout, and cerr have to exist, but it also prevents code from getting access to the file descriptors. So if you need to open a file with O_CLOEXEC, or receive a file descriptor over a Unix-domain socket, or call fsync or fstat or fchmod on a file descriptor, you basically need to duplicate a bunch of logic that's already in the standard library to use iostream.

0

There are 0 answers