Using unique_ptr to control a file descriptor

c++, c++11, gcc4.7, smart-pointers, unique-ptr

Solution

The type exposed by the `Deleter::pointer` must satisfy the `NullablePointer` requirements. Chief among them, this expression must be legal: `Deleter::pointer p = nullptr;`. Of course, `nullptr` is pretty much defined by the fact that it cannot be implicitly converted to a number, thus this doesn't work.

You'll have to use a type which can be implicitly constructed with `std::nullptr_t`. Something like this:

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;
};

You can use that as the `Deleter::pointer` type.

Problem

In theory, I should be able to use a custom pointer type and deleter in order to have `unique_ptr` manage an object that is not a pointer. I tried the following code: ``` #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 ``` This doesn't work (gcc 4.7 with the `-std=c++11` parameter). It responds with the following errors: ``` 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!=' ``` From delving into the definition of `unique_ptr`, I can see two problems that prevent it from working. The first, which seems in clear violation of the standard, is that the destructor for `unique_ptr` compares the "pointer" (which is, as per my definition, an int) to `nullptr` in order to see whether it is initialized or not. This is in contrast to the way it reports it through the boolean conversion, which is to compare it to `"pointer()"` (an uninitialized "pointer"). This is the cause of the errors I am seeing - an integer is not comparable to a `nullptr`. The second problem is that I need some way to tell `unique_ptr` what an uninitialized value is. I want the following snippet to work: ``` unique_fd fd( open(something...) ); if( !fd ) throw errno_exception("Open failed"); ``` For that to work, `unique_ptr` needs to know that an "uninitialized value" is -1, as zero is a valid file descriptor. Is this a bug in `gcc`, or am I trying to do something here that simply cannot be done?

Original source

Related problems