【发布时间】:2014-03-01 21:16:08
【问题描述】:
我想围绕文件描述符创建一个 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”。我想过制作一个自定义分配器来指向一个已经分配的块,但这似乎有点矫枉过正。你们有什么建议可以简化一下吗?
【问题讨论】:
-
考虑改用
std::shared_ptr<file_descriptor> -
@CaptainObvlious:我不能:那需要重写所有使用这个类的代码。此外,它改变了类的“契约”,即类的用户将负责共享资源。现在
shared_ptr是一个实现细节,对用户隐藏。 -
shared_ptr表示生命周期语义,实际上不应该隐藏。file_descriptor设计中的缺陷应该清楚地表明您设计的其余部分存在缺陷。我建议将这些作为一个整体解决并使用std::shared_ptr<file_descriptor>,否则您的设计将继续受到影响并且变得越来越难以维护。 -
@CaptainObvlious 您能否详细说明为什么将
std::shared_ptr作为类实现的一部分是一个缺陷?我不明白那部分
标签: c++ c++11 file-descriptor raii