C++ Logo


Advanced search

Re: [std-proposals] Construct an iostream from a file descriptor

From: Brian Bi <bbi5291_at_[hidden]>
Date: Fri, 2 Sep 2022 12:28:30 -0400
On Fri, Sep 2, 2022 at 12:15 PM Arthur O'Dwyer via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Fri, Sep 2, 2022 at 6:32 AM Peter C++ via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>> I think it is doable and desirable. i even was of the impression it would
>> already work,but at least not as of what is in the std.
>> issues:
>> - [...] should adoption also work from a FILE*?
>> - can there be destruction without close?
> On 2 Sep 2022, at 11:37, Paul Fee via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>> POSIX defines fdopen(), which takes ownership of a low level file
>> descriptor and returns a FILE* with which a user can perform buffered I/O.
>> There doesn't appear to be a similar feature in C++, though non-standard
>> workarounds exist, such as __gnu_cxx::stdio_filebuf.
>> https://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor
>> Are there issues that would block standardisation of such a facility?
>> Perhaps it's because fdopen() is part of POSIX rather than ISO C, hence
>> file descriptors themselves may not be universally portable.
>> Paul: The feature "turn a file descriptor into a FILE" already exists in
> both C and C++, *on POSIX platforms*; the POSIX-standard facility is
> called `fdopen`.
> File descriptors are a POSIX-standard thing. File descriptors don't exist,
> per se, on non-POSIX platforms. So the situation re "turn a file descriptor
> into a FILE" is already in the best possible state it could ever be in.
> However, then there's the next step: "turn a FILE into an ifstream,
> ofstream, or fstream." These are things that exist in every standard C++
> implementation, because the C++ standard defines both `FILE` (cstdio) and
> iostreams. It would be quite reasonable to propose a way to convert a
> `FILE` into an `{if,of,f}stream`, and/or vice versa.
> However, you'll have to figure out what is the right API for this. POSIX
> uses plain old `int` for all kinds of file descriptors, regardless of
> readability/writeability. C and C++ use `FILE*` for all kinds of files,
> regardless of readability/writeability. But the C++ iostreams library uses *different
> types* — std::istream for readable files, std::ostream for writeable
> files. What happens if I do
> FILE *fp = fopen("hello.txt", "r");
> std::ofstream out = std::ofstream(std::from_file, fp);
> Does this throw an exception? Is it library UB? A proposal would have to
> specify this kind of thing.
> Another thing you'll need to figure out — and probably by actually trying
> to implement this in a real library or two, not just on paper — is whether
> it's even possible to create a plain `std::ofstream` from a `FILE`, or
> whether you really need to create a whole new derived class, e.g.
> `std::ofilestream` (by analogy to `ostringstream`). And then you'll have to
> decide whether an `ofilestream` IS-AN `ofstream` or merely an `ostream`. See
> https://quuxplusone.github.io/blog/2018/11/26/remember-the-ifstream/

Are there any real-world implementations of `std::ifstream` and
`std::ofstream` that do not internally delegate to the C `FILE` API?

If the answer is "no" then I think it would not be difficult to require the
standard library to provide a facility to convert `FILE*`s into actual
`std::ifstream`s and `std::ofstream`s.

If the answer is "yes" then there might be someone who complains about that
proposal, since they might have to add something to their `std::ifstream`
and `std::ofstream` that would violate the "you don't pay for what you
don't use" principle. I say propose it and wait and see if someone
complains. If someone does complain, then amend the proposal.

> Completely off the top of my head, I'd expect the "right" design would be
> new classes analogous to <sstream>:
> #include <filestream>
> class ifilestream : public istream {};
> class ofilestream : public ostream {};
> class iofilestream : public iostream {};
> And by the way, I'm sure you could write these classes today in standard
> C++, if you really wanted to. Nico Josuttis's "fdstream" implementation is
> only 200 lines long for the whole thing; replacing the `int fd` and `write`
> with `FILE *fp` and `fwrite` probably wouldn't be very hard.
> http://www.josuttis.com/cppcode/fdstream.html
> Peter asks: Can there be destruction without (explicit) close? — Yes, the
> semantics of `fstream` are that if you destroy an `fstream` without
> explicitly `.close()`'ing it first, then the destructor will close it for
> you (and swallow any filesystem errors that might occur).
> https://stackoverflow.com/questions/4802494/do-i-need-to-close-a-stdfstream
> Paul also wrote:
> > Looking at std::format [C++20], it outputs strings. std::print [C++23],
> outputs to FILE*. Does this suggest iostream gets sidelined and FILE*
> becomes more preferable?
> No, at least not any more than it has been sidelined in real code for 20+
> years.
> std::print has overloads taking `std::ostream&` alongside overloads taking
> `FILE*`, so you will be able to write *either* of these:
> std::println(stdout, "hello world!");
> std::println(std::cout, "hello world!");
> just as today you can write either of these:
> puts("hello world!");
> std::cout << "hello world!\n";
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2093r14.html#wording
> HTH,
> Arthur
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

*Brian Bi*

Received on 2022-09-02 16:28:43