Home > other >  how to pass custom deleter to std::unique_ptr using std::bind
how to pass custom deleter to std::unique_ptr using std::bind

Time:01-13

How to pass a custom deleter to std::unique_ptr using std::bind. This is my code

#include <iostream>
#include <memory>
#include <functional>

struct Sample
{
};
// Memory Pool Dummy Kind of Implementation
template<typename T>
class MemoryPool
{
public:
    T * AcquireMemory()
    {
        std::cout << "ACQUIRING MEMORY\n";
        return (new T());
    }
    void ReleaseMemory(T * ptr)
    {
        std::cout << "RELEASING MEMORY\n";
        delete ptr;
    }
};

int main()
{
    std::shared_ptr<MemoryPool<Sample>> memoryPoolPtr = std::make_shared<
            MemoryPool<Sample>>();
    std::shared_ptr<Sample> p3(memoryPoolPtr->AcquireMemory(),
            std::bind(&MemoryPool<Sample>::ReleaseMemory, memoryPoolPtr.get(),
                    std::placeholders::_1));

    std::cout << p3.use_count() << std::endl;

    std::unique_ptr<MemoryPool<Sample>> un = std::make_unique<MemoryPool<Sample>>();
// getting compiler error for the below line
    std::unique_ptr<Sample> unq(un->AcquireMemory(), std::bind(&MemoryPool<Sample>::ReleaseMemory, un.get(),
                    std::placeholders::_1));

    return 0;
}

This is the error message I'm getting error: no matching function for call to 'std::unique_ptr<Sample>::unique_ptr(Sample*, std::_Bind_helper<false, void (MemoryPool<Sample>::*)(Sample*), MemoryPool<Sample>*, const std::_Placeholder<1>&>::type)'.

CodePudding user response:

std::unique_ptr doesn't store the deleter type-erased in a shared state block like shared_ptr. So you might have to explicitly name the type (or a type it's convertible into)

std::unique_ptr<MemoryPool<Sample>> un = std::make_unique<MemoryPool<Sample>>();
std::unique_ptr<Sample,std::function<void(Sample*)>> unq(
    un->AcquireMemory(),
    std::bind(
        &MemoryPool<Sample>::ReleaseMemory,
        memoryPoolPtr.get(),
        std::placeholders::_1
    )
);

Bonus meme: just use a lambda instead of std::bind

auto deleter = [alloc=un.get()](Sample* p){alloc->ReleaseMemory(p);};
auto unq = std::unique_ptr<Sample,decltype(deleter)>(
    un->AcquireMemory(), std::move(deleter)
);

CodePudding user response:

Like the other comments/answers pointed out, unique_ptr requires two template arguments with the 2nd argument being the deleter type.

Another alternative here is to create your own make_unique_with_deleter function. The standard std::make_unique forwards its arguments to the T constructor, so my example here is incomplete.

template <typename T, typename D>
auto convert_ptr_to_unique_with_deleter(T* ptr, const D& d)
{
   return std::unique_ptr<T, D>(ptr, d);
}

int main()
{
...

   auto unq = convert_ptr_to_unique(un->AquireMemory(), std::bind(&MemoryPool<Sample>::ReleaseMemory, un.get(),
                    std::placeholders::_1));
}

The advantage here is that this will work with any type T.

  •  Tags:  
  • Related