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
.