Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
174 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...