56

N3290 によると、std::unique_ptrコンストラクターで deleter 引数を受け入れます。

ただし、Windows の Visual C++ 10.0 または MinGW g++ 4.4.1 でも、Ubuntu の g++ 4.6.1 でも動作しません。

したがって、それについての私の理解が不完全または間違っているのではないかと恐れています。明らかに無視されているdeleter引数のポイントがわからないので、誰かが実際の例を提供できますか?

できれば、それがどのように機能するかについても確認したいと思いunique_ptr<Base> p = unique_ptr<Derived>( new Derived )ます。

おそらく、例をバックアップするために標準からのいくつかの文言を使用して、つまり、使用しているコンパイラが何であれ、実際に行うべきことを実行するということですか?

4

4 に答える 4

46

これはMSVC10で機能します

int x = 5;
auto del = [](int * p) { std::cout << "Deleting x, value is : " << *p; };
std::unique_ptr<int, decltype(del)> px(&x, del);

そしてgcc 4.5では、ここ

その例が期待どおりに機能していると思わない限り、標準に進むことはスキップします。

于 2011-11-25T21:52:38.890 に答える
27

以前のすべての回答を補完するために、次のように関数ポインターまたは同等のものを使用して、unique_ptr シグネチャを「汚染」することなく、カスタム デリータを使用する方法があります。

std::unique_ptr< MyType, myTypeDeleter > // not pretty

これは、次のように std::default_delete テンプレート クラスに特殊化を提供することで実現できます。

namespace std
{
template<>
class default_delete< MyType >
{
public:
  void operator()(MyType *ptr)
  {
    delete ptr;
  }
};
}

そして今、std::unique_ptr< MyType >この専門化を「見る」ものはすべて削除されます。すべてstd::unique_ptr< MyType >の人にとって必要なものではない可能性があることに注意してください。慎重にソリューションを選択してください。

于 2013-05-17T18:02:51.017 に答える
11

私の質問はすでにかなりよく答えられています。

しかし、人々が不思議に思った場合に備えて、私は aunique_ptr<Derived>を a に移動できunique_ptr<Base>、オブジェクトのデリータを記憶できるDerived、つまり、Base仮想デストラクタを持つ必要がない、という誤った考えを持っていました。それは間違っていました。Kerrek SB のコメントを「答え」として選択しますが、コメントに対してそれを行うことはできません。

@Howard : 以下のコードは、動的に割り当てられたデリータのコストがすぐにサポートされることを意味する必要があると私が信じていたことを達成する 1 つの方法を示していunique_ptrます。

#include <iostream>
#include <memory>           // std::unique_ptr
#include <functional>       // function
#include <utility>          // move
#include <string>
using namespace std;

class Base
{
public:
    Base() { cout << "Base:<init>" << endl; }
    ~Base() { cout << "Base::<destroy>" << endl; }
    virtual string message() const { return "Message from Base!"; }
};

class Derived
    : public Base
{
public:
    Derived() { cout << "Derived::<init>" << endl; }
    ~Derived() { cout << "Derived::<destroy>" << endl; }
    virtual string message() const { return "Message from Derived!"; }
};

class BoundDeleter
{
private:
    typedef void (*DeleteFunc)( void* p );

    DeleteFunc  deleteFunc_;
    void*       pObject_;

    template< class Type >
    static void deleteFuncImpl( void* p )
    {
        delete static_cast< Type* >( p );
    }

public:
    template< class Type >
    BoundDeleter( Type* pObject )
        : deleteFunc_( &deleteFuncImpl< Type > )
        , pObject_( pObject )
    {}

    BoundDeleter( BoundDeleter&& other )
        : deleteFunc_( move( other.deleteFunc_ ) )
        , pObject_( move( other.pObject_ ) )
    {}

    void operator() (void*) const
    {
        deleteFunc_( pObject_ );
    }
};

template< class Type >
class SafeCleanupUniquePtr
    : protected unique_ptr< Type, BoundDeleter >
{
public:
    typedef unique_ptr< Type, BoundDeleter >    Base;

    using Base::operator->;
    using Base::operator*;

    template< class ActualType >
    SafeCleanupUniquePtr( ActualType* p )
        : Base( p, BoundDeleter( p ) )
    {}

    template< class Other >
    SafeCleanupUniquePtr( SafeCleanupUniquePtr< Other >&& other )
        : Base( move( other ) )
    {}
};

int main()
{
    SafeCleanupUniquePtr< Base >  p( new Derived );
    cout << p->message() << endl;
}
于 2011-11-26T10:38:11.893 に答える
6

これは機能します。破壊は適切に行われます。

class Base
{
    public:
     Base() { std::cout << "Base::Base\n"; }
     virtual ~Base() { std::cout << "Base::~Base\n"; }
};


class Derived : public Base
{
    public:
     Derived() { std::cout << "Derived::Derived\n"; }
     virtual ~Derived() { std::cout << "Derived::~Derived\n"; }
};

void Delete(const Base* bp)
{
    delete bp;
}

int main()
{
    std::unique_ptr<Base, void(*)(const Base*)> ptr = std::unique_ptr<Derived, void(*)(const Base*)>(new Derived(), Delete);
}
于 2011-11-25T22:02:08.047 に答える