Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any RAII file handle already implemented?

Tags:

c++

io

raii

A RAII file handle looks pretty basic so I guess it has already been implemented? But I couldn't find any implementation. I found file_descriptor in boost::iostreams but I don't know if it's what I'm looking for.

like image 358
valentin Avatar asked Apr 01 '14 02:04

valentin


2 Answers

std::fstreams support RAII-style usage - they can be opened and even tested at construction, and they're automatically flushed and closed in the destructor, though you could miss errors if you just assume that works so you may want to do something more explicit in code if you need the robustness.

For example:

if (std::ifstream input(filename))
    ... use input...
else
    std::cerr << "unable to open '" << filename << "'\n";

If you really want to use file descriptors, you can tune something like the following to taste. It's a bit longer than something that just invokes close, but if you want to do robust programming you need to check for and handle errors somehow....

struct Descriptor
{
    Descriptor(int fd, const char* filename = nullptr)
      : fd_(fd), filename_(filename)
    {
        if (fd < 0)
        {
            std::ostringstream oss;
            oss << "failed to open file";
            if (filename_) oss << " '" << filename_ << '\'';
            oss << ": " << strerror(errno);
            throw std::runtime_error(oss.str());
        }
    }
    ~Descriptor()
    {
        if (fd_ != -1 && close(fd_) == -1)
        {
            // throwing from destructors risks termination - avoid...
            std::cerr << "failed to close file";
            if (filename_) std::cerr << " '" << filename_ << '\'';
            std::cerr << ": " << strerror(errno) << std::endl;
        }
    }
    operator int() const { return fd_; }

  private:
    int fd_;
};

Usage:

try
{
    Descriptor fd(open(filename, O_RDONLY), filename);
    int nbytes = read(fd, ...);
    ...
}
catch ...
like image 157
Tony Delroy Avatar answered Sep 19 '22 17:09

Tony Delroy


Depends on what exactly you want.

If you really want a scoped handle, use:

std::unique_ptr<HANDLETYPE, closehandletypefunction> smartpointer;

For FILE pointers, this would look like

std::unique_ptr<FILE, int (*)(FILE *)> f(fopen("myfile.txt", "a"), fclose);

The FILE* can then be gotten with f.get(). The same thing would work with file descriptors (open and close from <fcntl.h> and <unistd.h>, respectively).

The preferred C++ way is wrapping the handle in an object with thousands of members to do everything though.

like image 39
Deduplicator Avatar answered Sep 22 '22 17:09

Deduplicator