Using abstract deleter with std :: unique_ptr

I want to have a runtime interface that offers some creation methods. These methods return unique_ptr<T>, and I want to enable arbitrary deletion by the create class. The fact is that I definitely do not want the interface to offer these methods directly - they should be available only upon destruction unique_ptr<T, SomeCustomDel>. Now I understand what I can use std::unique_ptr<T, std::function<void(T*)>>, but I would prefer not because I just do not need this level of abstraction, and I do not want to pay for the allocation of the heap.

Any suggestions?

+5
source share
5 answers

, unique_ptr<T, void(*)(void*)>? .

, , - :

class impl
{
public:
    virtual ~impl();

    virtual void operator()(void*) = 0;
    virtual void other_functionality() = 0;
};

class my_deleter
{
    impl* p_;
public:
    ...
    void operator()(void* p) {(*p_)(p);}
    void other_functionality() {p_->other_functionality();}
    ...
};

, , .

+2

, "" std::unique_ptr. unique_ptr, , std::shared_ptr.

, , , std::unique_ptr<T,std::function<void(T*)>>. , .

, , std::function. - , , . , ( , boost::function 32 ).

A . . . , . , deleter , .

, , . . - , , , , .

+2

.

1: , , char , :

template<class T>
void simply_delete(T* ptr, const unsigned char*) {
    delete ptr;
}

template<class T, int StateSize>
struct my_deleter {
    void (*funptr)(T*,const unsigned char*);
    array<unsigned char,StateSize> state;

    my_deleter() : funptr(&simply_delete<T>) {}

    void operator()(T* ptr) const {
        funptr(ptr,StateSize>0 ? &state[0] : nullptr);
    }
};

template<class T>
using upi = unique_ptr<T,my_deleter<T,sizeof(void*)>>;

upi<T>, , . , function<> deleter, " ". , function<> (, ), . , .:)

2: shared_ptr unique_ptr . Derived- > Base. , , std:: allocate_shared.

+1

, . - .

, "" std::unique_ptr. unique_ptr , std::shared_ptr.

. . unique_ptr , . , . .:-) . , -, ( unique_ptr ).

#include <memory>
#include <type_traits>

namespace detail
{

class impl
{
public:
    virtual ~impl() {};
};

template <class T, class D>
class erase_type
    : public impl
{
    T* t_;
    D d_;

public:
    explicit erase_type(T* t)
            noexcept(std::is_nothrow_default_constructible<D>::value)
        : t_(t)
    {}

    erase_type(T* t, const D& d)
            noexcept(std::is_nothrow_copy_constructible<D>::value)
        : t_(t),
          d_(d)
       {}

    erase_type(T* t, D&& d)
            noexcept(std::is_nothrow_move_constructible<D>::value)
        : t_(t),
          d_(std::move(d))
       {}

    virtual ~erase_type()
    {
        if (t_)
            d_(t_);
    }

    erase_type(const erase_type&) = delete;
    erase_type& operator=(const erase_type&) = delete;
};

}  // detail

template <class T>
class my_pointer
{
    T* ptr_;
    detail::impl* impl_;

public:
    my_pointer() noexcept
        : ptr_(nullptr),
          impl_(nullptr)
    {}

    template <class Y>
    explicit my_pointer(Y* p)
        : ptr_(static_cast<T*>(p)),
          impl_(nullptr)
    {
        std::unique_ptr<Y> hold(p);
        impl_ = new detail::erase_type<Y, std::default_delete<Y>>(p);
        hold.release();
    }

    template <class Y, class D>
    explicit my_pointer(Y* p, D&& d)
        : ptr_(static_cast<T*>(p)),
          impl_(nullptr)
    {
        std::unique_ptr<Y, D&> hold(p, d);
        typedef
            detail::erase_type<Y, typename std::remove_reference<D>::type>
            ErasedType;
        impl_ = new ErasedType(p, std::forward<D>(d));
        hold.release();
    }

    ~my_pointer()
    {
        delete impl_;
    }

    my_pointer(my_pointer&& p) noexcept
        : ptr_(p.ptr_),
          impl_(p.impl_)
    {
        p.ptr_ = nullptr;
        p.impl_ = nullptr;
    }

    my_pointer& operator=(my_pointer&& p) noexcept
    {
        delete impl_;
        ptr_ = p.ptr_;
        impl_ = p.impl_;
        p.ptr_ = nullptr;
        p.impl_ = nullptr;
        return *this;
    }

    typename std::add_lvalue_reference<T>::type
    operator*() const noexcept
        {return *ptr_;}

    T* operator->() const noexcept
        {return ptr_;}
};

, unique_ptr (, shared_ptr), , , noexcept. " ". .: -)

+1

, ; unique_ptr . . @deft_code, .

, :

, T - . makeT(), func T *:

std::unique_ptr<T, std::function<void(T*)>> p(makeT(), [](T* p){p.delete();});

, , .

For C ++ 11 raw eyes, the syntax [] (...) is lambda.

As mentioned in other answers, this is not a “function pointer” in the sense of C, but a C ++ object being called, which is really tiny, and should have little overhead for moving it around.

0
source

All Articles