我想在文件描述符周围创建一个RAII包装器。由于对象可能围绕线程传递,它实际上是一个共享资源:这就是我使用shared_ptr
和自定义析构函数进行第一次实现的原因。
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;
};
自定义析构函数非常简单:
struct file_descriptor_closer
{
void operator()(int * const fd) noexcept { if (fd) close(*fd); delete fd; }
};
现在我发现设计很糟糕,即因为“新的int”。我想过将自定义分配器指向已经分配的块,但这似乎有点过分了。你们有建议简化这个吗?
答案 0 :(得分:4)
shared_ptr
。乍一看,如果我要在线程之间共享一个file_descriptor,我会自己制作一个shared_ptr<file_descriptor>
来解决我不知道内部已经在做的问题。
答案 1 :(得分:1)
使用一些温和的暴力:
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;
};
答案 2 :(得分:-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;
}