11

unique_ptr理論的には、ポインタではないオブジェクトを管理するために、カスタム ポインタ タイプとデリータを使用できるはずです。次のコードを試しました:

#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

これは機能しません (-std=c++11パラメーターを使用した gcc 4.7)。次のエラーで応答します。

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、それが機能しない 2 つの問題があることがわかります。1つ目は、明らかに標準に違反しているように見えますが、初期化されているかどうかを確認するために、デストラクタunique_ptrが「ポインタ」(私の定義によればint)を比較することです。nullptrこれは、"pointer()"(初期化されていない「ポインター」) と比較するブール変換によって報告する方法とは対照的です。これが私が見ているエラーの原因です - 整数はnullptr.

2 番目の問題は、初期化されunique_ptrていない値が何であるかを伝える何らかの方法が必要なことです。次のスニペットを機能させたい:

unique_fd fd( open(something...) );

if( !fd )
    throw errno_exception("Open failed");

それが機能するにunique_ptrは、ゼロが有効なファイル記述子であるため、「初期化されていない値」が -1 であることを知る必要があります。

これは のバグですかgcc、それとも単に実行できないことをここで行おうとしていますか?

4

9 に答える 9

10

次のような簡単なことはできますか?

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ポインターを管理するために設計されたを使用しなければならなかった理由がわかりません。

于 2013-04-02T11:14:09.553 に答える
0

ニコル・ボーラスのクラスをより一般化する:

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
// ...

デフォルトのテンプレート パラメータ値を使用する必要があるかどうかがわかりません。

于 2016-06-19T08:40:30.397 に答える
0

この解決策は、ニコル・ボーラスの回答に基づいています。

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;
于 2015-06-26T08:45:26.720 に答える
0

通常、共有所有権のセマンティクスの方が適切であり、deleter のタイプが消去されるため、ハンドルの有効期間を管理するのshared_ptrではなく、使用することをお勧めします。次のヘルパーが必要です。unique_ptrint

namespace handle_detail
{
    template <class H, class D>
    struct deleter
    {
        deleter( H h, D d ): h_(h), d_(d) { }
        void operator()( H * h ) { (void) d_(h_); }
        H h_;
        D d_;
    };
}

template <class H,class D>
std::shared_ptr<H const>
make_handle( H h, D d )
{
    std::shared_ptr<H> p((H *)0,handle_detail::deleter<H,D>(h,d));
    return std::shared_ptr<H const>(
        p,
        &std::get_deleter<handle_detail::deleter<H,D> >(p)->h_ );
}

ファイル記述子で使用するには:

int fh = open("readme.txt", O_RDONLY); // Check for errors though.
std::shared_ptr<int const> f = make_handle(fh, &close);
于 2019-08-08T06:03:57.163 に答える