使用unique_ptr来控制文件描述符

理论上,我应该能够使用自定义的指针types和删除器,以使unique_ptrpipe理不是指针的对象。 我试了下面的代码:

#ifndef UNIQUE_FD_H #define UNIQUE_FD_H #include <memory> #include <unistd.h> struct unique_fd_deleter { typedef int pointer; // Internal type is a pointer void operator()( int fd ) { close(fd); } }; typedef std::unique_ptr<int, unique_fd_deleter> unique_fd; #endif // UNIQUE_FD_H 

这是行不通的(gcc 4.7和-std = c ++ 11参数)。 它回应以下错误:

 In file included from /usr/include/c++/4.7/memory:86:0, from test.cc:6: /usr/include/c++/4.7/bits/unique_ptr.h: In instantiation of 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = int; _Dp = unique_fd_deleter]': test.cc:22:55: required from here /usr/include/c++/4.7/bits/unique_ptr.h:172:2: error: invalid operands of types 'int' and 'std::nullptr_t' to binary 'operator!=' 

从深入研究unique_ptr的定义,我可以看到两个问题阻止它的工作。 第一个看起来明显违背了标准,就是unique_ptr的析构函数将“指针”(也就是,按照我的定义,一个int)与nullptr进行比较,以查看它是否被初始化。 这与它通过布尔转换来报告它的方式形成对比,它将它与“pointer()”(未初始化的“指针”)进行比较。 这是我所看到的错误的原因 – 一个整数是不可比较的nullptr。

第二个问题是我需要一些方法来告诉unique_ptr什么是未初始化的值。 我想要以下片段工作:

 unique_fd fd( open(something...) ); if( !fd ) throw errno_exception("Open failed"); 

为此,unique_ptr需要知道“未初始化的值”是-1,因为零是有效的文件描述符。

这是gcc中的一个bug,还是我想在这里做一些根本无法做到的事情?

谢谢Shachar

Solutions Collecting From Web of "使用unique_ptr来控制文件描述符"

Deleter::pointer公开的类型必须满足NullablePointer要求 。 其中最主要的是,这个表达式必须是合法的: Deleter::pointer p = nullptr; 。 当然, nullptr 不能被隐式转换为int ,所以这是行不通的。

你将不得不使用一个可以用std::nullptr_t隐式构造的类型。 像这样的东西:

 struct file_desc { file_desc(int fd) : _desc(fd) {} file_desc(std::nullptr_t) : _desc(-1) {} operator int() {return _desc;} bool operator ==(const file_desc &other) const {return _desc == other._desc;} bool operator !=(const file_desc &other) const {return _desc != other._desc;} bool operator ==(std::nullptr_t) const {return _desc == -1;} bool operator !=(std::nullptr_t) const {return _desc != -1;} int _desc; }; 

你可以使用它作为Deleter::pointer类型。

你能做一些简单的事情吗?

 class unique_fd { public: unique_fd(int fd) : fd_(fd) {} unique_fd(unique_fd&& uf) { fd_ = uf.fd_; uf.fd_ = -1; } ~unique_fd() { if (fd_ != -1) close(fd_); } explicit operator bool() const { return fd_ != -1; } private: int fd_; unique_fd(const unique_fd&) = delete; unique_fd& operator=(const unique_fd&) = delete; }; 

我不明白为什么你必须使用unique_ptr ,它是专门用来管理指针的。

这个解决方案是基于Nicol Bolas的回答:

 struct FdDeleter { typedef int pointer; void operator()(int fd) { ::close(fd); } }; typedef std::unique_ptr<int, FdDeleter> UniqueFd; 

它简短,但你必须避免比较UniqueFd实例与nullptr并将其用作布尔表达式:

 UniqueFd fd(-1, FdDeleter()); //correct //UniqueFd fd(nullptr, FdDeleter()); //compiler error if (fd.get() != -1) //correct { std::cout << "Ok: it is not printed" << std::endl; } if (fd) //incorrect, avoid { std::cout << "Problem: it is printed" << std::endl; } if (fd != nullptr) //incorrect, avoid { std::cout << "Problem: it is printed" << std::endl; } return 1; 

尼古拉·布拉斯班更一般:

 template<class T=void*,T null_val=nullptr> class Handle { public: Handle(T handle):m_handle(handle){} Handle(std::nullptr_t):m_handle(null_val){} operator T(){return m_handle;} bool operator==(const Handle& other) const {return other.m_handle==m_handle;} private: T m_handle; }; typedef Handle<int,-1> FileDescriptor; typedef Handle<GLuint,0> GlResource; // according to http://stackoverflow.com/questions/7322147/what-is-the-range-of-opengl-texture-id // ... 

我不确定是否应该有默认的模板参数值。