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.