user7610
user7610

Reputation: 28761

Can I succintly declare std::unique_ptr with custom deleter?

I am dealing with C types which have a new_ and free_ methods associated.

The type signature of new_ may vary, but the free_ is always a void free_something(something*);

Currently, I am declaring my unique_ptrs this way, which seems overly verbose:

std::unique_ptr<qdr_link_t, decltype(&free_qdr_link_t)> link{new_qdr_link_t(), free_qdr_link_t};

Can I do this with less ceremony, somehow? I saw a neat solution for a situation when my deallocator is the std::free() function, at https://stackoverflow.com/a/43626234/1047788. I tried to create a version where I could parameterize the deallocator, but I got nowhere with it.

The best I could think of was to create a macro from the above declaration.

Upvotes: 3

Views: 340

Answers (2)

eerorika
eerorika

Reputation: 238311

I've been using following:

template <auto fptr>
struct Caller {
    template <class... Args>
    auto
    operator()(Args&&... args) noexcept
    {
        return fptr(std::forward<Args...>(args)...);
    }
};

Example usage:

using qdr_freer = Caller<free_qdr_link_t>;

using unique_qdr_ptr = std::unique_ptr<qdr_link_t, qdr_freer>;

[[nodiscard]] unique_qdr_ptr
make_qdr_unique()
{
    return unique_qdr_ptr{new_qdr_link_t()};
}

This implementation uses C++17 features though, so it requires a few changes to work in C++11.


Note that although Caller may seem like a good fit with std::free, they are strictly speaking not compatible because std::free is a standard library function not designated as "addressable".

Upvotes: 3

Asteroids With Wings
Asteroids With Wings

Reputation: 17454

Let the language do the hard work!

#include <memory>

struct qdr_link_t;
qdr_link_t* new_qdr_link_t();
void free_qdr_link_t(qdr_link_t*);

template <typename T, typename Deleter>
auto make_unique_ptr(T* raw, Deleter deleter)
{
    return std::unique_ptr<T, Deleter>(raw, deleter);
}

//std::unique_ptr<qdr_link_t, decltype(&free_qdr_link_t)> link{new_qdr_link_t(), free_qdr_link_t};
auto link = make_unique_ptr(new_qdr_link_t(), free_qdr_link_t);

Add std::forward to taste (if you care).


For C++11, you'll need to add the trailing return type -> std::unique_ptr<T, Deleter> to make_unique_ptr, or just put that in the "normal" return type.

Upvotes: 1

Related Questions