c++fileraii

Is it smart to use RAII to manage files?


I wanted to create a class Channel that facilitates file writes in a special way. It was clear to me at first that I call open() on the file in the constructor and close() on the file descriptor in the destructor. But this would mean that I have to throw in the destructor if close() fails for some reason. Is it smart to use RAII for file management anyway? Should I throw in the destructor?

Live demo:

#include <iostream>
#include <fcntl.h> /* open */
#include <unistd.h> /* close */
#include <stdexcept>
#include <filesystem>

class Channel
{
public:
    Channel(std::filesystem::path path_to_file)
    {
        _fd = open(path_to_file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        if (!_fd)
        {
            throw std::runtime_error{ "Failed to open file" };
        }
    }

    ~Channel()
    {
        int r = close(_fd);
        if (r < 0)
        {
            // ... ?
        }
    } 

private:
    int _fd;
};

int main()
{
    Channel("/home/user/myfile.txt");
}

Solution

  • It has been already mentioned in a comment. Compare to what the standard library does:

     { 
          std::ifstream f{"path/to/file"}; 
          f >> data;
          // f.close();  // possible but usually unnecessary
     }
    

    The situation with std::ifstream is exactly what @john explains in their comment: The stream closes the file in its destructor. Any exceptions or errors encountered during that go unnoticed (because one should not throw from a destructor). If you want to check if closing the file succeeded you can call close explicitly (and that's about the only reason you want to call close explicitly).

    Yes RAII is a good way to handle files. I remember Bjarne using that as example for why RAII is such a cool thing: It applies not only to memory, hence is more generally applicable compared to eg garbage collection.