How does the custom deleter of std::unique_ptr work?

后端 未结 4 473
青春惊慌失措
青春惊慌失措 2020-11-27 11:47

According to N3290, std::unique_ptr accepts a deleter argument in its constructor.

However, I can\'t get that to work with Visual C++ 10.0 or MinGW g++

相关标签:
4条回答
  • 2020-11-27 12:11

    This works. The destruction happens properly.

    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);
    }
    
    0 讨论(0)
  • 2020-11-27 12:13

    To complement all previous answers, there is a way to have a custom deleter without having to "pollute" the unique_ptr signature by having either a function pointer or something equivalent in it like this:

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

    This is achievable by providing a specialization to the std::default_delete template class, like this:

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

    And now all std::unique_ptr< MyType > that "sees" this specialization will be deleted with it. Just be aware that it might not be what you want for all std::unique_ptr< MyType >, so chose carefully your solution.

    0 讨论(0)
  • 2020-11-27 12:14

    This works for me in MSVC10

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

    And on gcc 4.5, here

    I'll skip going to the standard, unless you don't think that example is doing exactly what you'd expect it to do.

    0 讨论(0)
  • 2020-11-27 12:31

    My question has been pretty well answered already.

    But just in case people wondered, I had the mistaken belief that a unique_ptr<Derived> could be moved to a unique_ptr<Base> and would then remember the deleter for the Derived object, i.e., that Base would not need to have a virtual destructor. That was wrong. I'd select Kerrek SB's comment as "the answer", except one cannot do that for a comment.

    @Howard: the code below illustrates one way to achieve what I believed the cost of a dynamically assigned deleter had to mean that unique_ptr supported out of the box:

    #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;
    }
    
    0 讨论(0)
提交回复
热议问题