Graznarak
Graznarak

Reputation: 3692

Using std::make_unique with a custom deleter

In using std::unique_ptr with a custom deleter I desire to use std::make_unique rather than a raw new. I am using VC++2013. It appears to me that there is no way to use std::unique_ptr if you are using a custom deleter. Did I miss something or is this really the case?


Additional Information:

I am using a std::unique_ptr<HANDLE, custom_deleter> to hold a Windows HANDLE for an opened COM port.

I could write a custom RAII class for this, and it wouldn't be terribly difficult, but I was seeing how hard/difficult/bad it would be to use std::unique_ptr.

Upvotes: 56

Views: 42091

Answers (3)

Jon Ringle
Jon Ringle

Reputation: 143

Here is a way to wrap c style memory management into a std::unique_ptr using a custom deleter that calls a custom free function. This has a make function helper similar to std::make_unique LIVE:

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

// Some C style code that has some custom free function ptr...
extern "C" {

struct ABC { };

enum free_type_e {
    FREE_ALL,
    FREE_SOME
};

typedef void (free_f)(enum free_type_e free_type, void *ptr);
struct some_c_ops { free_f* free_op; };

void MY_free(enum free_type_e free_type, void *ptr)
{
    printf("%s:%d ptr=%ld\n", __func__, __LINE__, (long)ptr);
    (void)free_type;
    free(ptr);
}

}; // extern "C"

template<typename T>
using c_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>;

template <typename T>
c_unique_ptr<T> make_c_unique(some_c_ops* op, free_type_e free_type)
{
    return c_unique_ptr<T>(static_cast<T*>(calloc(1, sizeof(T))),
                           std::bind(op->free_op, free_type, std::placeholders::_1));
}

void foo(c_unique_ptr<ABC> ptr)
{
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) <<     std::endl;
}

int main()
{
    some_c_ops ops = { MY_free };
    c_unique_ptr<ABC> ptr = make_c_unique<ABC>(&ops, FREE_ALL);
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;

    foo(std::move(ptr));

    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;
}

Possible output:

main:48 ptr=50511440
foo:40 ptr=50511440
MY_free:20 ptr=50511440
main:53 ptr=0

Upvotes: 3

sleepy1771
sleepy1771

Reputation: 319

As far as I know there is no make_unique function in the C++11 standard. See

So I would assume that the make_unique is an implementation from Microsoft that is at least not included in the standard.

But nevertheless you can use a custom deleter with unique_ptr. When using unique_ptr you have to specify the type of the deleter as a second template argument and then pass an appropriate object to the constructor.

Upvotes: -5

Kerrek SB
Kerrek SB

Reputation: 477010

The whole point of make_unique is to encapsulate the notion of "use new to create a T from given constructor arguments and use delete to destroy it".

If you wanted a custom deleter, you would also have to specify how to create the object, and then there would be nothing more gained from having the emplacing maker function.

I wrote some examples of custom maker functions for certain unique resource handles in this post.

Upvotes: 48

Related Questions