On Fri, Sep 2, 2022 at 12:15 PM Arthur O'Dwyer via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Fri, Sep 2, 2022 at 6:32 AM Peter C++ via Std-Proposals <std-proposals@lists.isocpp.org> 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@lists.isocpp.org> 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.


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

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.

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).

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";

HTH,
Arthur
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals


--
Brian Bi