How can I create a RAII file descriptor without creating a new int

I want to create a RAII wrapper around a file descriptor. Since an object can be passed around threads, it really is a shared resource: that’s why I made the first implementation using shared_ptrwith a custom destructor.

struct file_descriptor
{
    file_descriptor( const std::string & pathname, int flags )
        :m_fd( initialize( pathname, flags ) )
    {
    }

    file_descriptor( const int opened_fd )
        :m_fd( initialize( opened_fd ) )
    {
    }

    operator int() const { return *m_fd; }

private:
    std::shared_ptr<int> initialize( const int opened_fd )
    {
        std::shared_ptr<int> ptr_to_fd;

        try
        {
            int * shared_fd = new int;
            ptr_to_fd = std::shared_ptr<int>( shared_fd, file_descriptor_closer() );
            *shared_fd = opened_fd;
        }
        catch( std::bad_alloc & )
        {
            close( opened_fd );
            throw;
        }

        return ptr_to_fd;
    }

    std::shared_ptr<int> initialize( const std::string & pathname, int flags )
    {
        const int fd = open( pathname.c_str(), flags );        
        if (fd < 0)
            throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );

        return initialize( fd );
    }
    std::shared_ptr<int> m_fd;
};

The custom destructor is pretty simple:

struct file_descriptor_closer
{
    void operator()(int * const fd) noexcept { if (fd) close(*fd); delete fd; }
}; 

Now I find the design terrible, namely because of the "new int". I was thinking of making a custom allocator to point to an already allocated block, but that seems redundant. Do you have a suggestion to simplify this?

+4
source share
3 answers

, . RAII . - RAII. , file_descriptor , shared_ptr . , file_descriptor , shared_ptr<file_descriptor> , , , .

+4

:

struct file_descriptor_closer
{
    void operator()(void* fd) noexcept { if (fd) close(reinterpret_cast< int >(fd)); }
}; 
struct file_descriptor
{
    file_descriptor( const std::string & pathname, int flags )
        :m_fd( initialize( pathname, flags ) )
    {
    }

    file_descriptor( const int opened_fd )
        :m_fd( initialize( opened_fd ) )
    {
    }

    operator int() const { return reinterpret_cast< int >(m_fd.get()); }

private:
    std::shared_ptr<void> initialize( const int opened_fd )
    {
        try
        {
            return std::shared_ptr< void >( reinterpret_cast< void* >( opened_fd ), file_descriptor_closer() );
        }
        catch( std::bad_alloc & )
        {
            close( opened_fd );
            throw;
        }
    }

    std::shared_ptr<void> initialize( const std::string & pathname, int flags )
    {
        const int fd = open( pathname.c_str(), flags );        
        if (fd < 0)
            throw std::system_error( std::error_code(errno, std::system_category() ), "cannot create file descriptor" );

        return initialize( fd );
    }
    std::shared_ptr<void> m_fd;
};
+1

? - : http://ideone.com/m3kmaJ : http://ideone.com/Gs4Kb7

#include <iostream>
#include <sys/stat.h>
#include <fcntl.h>
#include <thread>
#include <memory>
#include <unistd.h>
#include <atomic>

class FD
{
    private:
        int fd;
        static int count;

    public:
        FD(const char* FilePath, int flags) : fd(open(FilePath, flags)) {++FD::count;}
        FD(const FD& other) : fd(other.fd) {++FD::count;}
        FD(FD&& other) : fd(other.fd) { other.fd = -1; }

        ~FD()
        {
            FD::count -= 1;
            if (FD::count == 0)
            {
                std::cout<<"Destroyed\n";
                if (is_open())
                    close(fd);
            }
        }

        bool is_open() {return fd != -1;}
        FD* operator &() {return nullptr;}
        operator int() {return fd;}

        FD& operator = (FD other)
        {
            fd = other.fd;
            FD::count += 1;
            return *this;
        }

        FD& operator = (FD&& other)
        {
            fd = other.fd;
            other.fd = -1;
            return *this;
        }
};

int FD::count = 0;

int main()
{
    FD fd = FD("Unicode.cpp", O_RDONLY);
    FD copy = fd;
    FD cpy = FD(copy);

    return 0;
}
-1

Source: https://habr.com/ru/post/1529601/


All Articles