Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::make_unique with a custom deleter

Tags:

c++

c++11

c++14

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.

like image 284
Graznarak Avatar asked Feb 14 '14 19:02

Graznarak


People also ask

Should I use make_unique?

It is recommended to use the 'make_unique/make_shared' function to create smart pointers. The analyzer recommends that you create a smart pointer by calling the 'make_unique' / 'make_shared' function rather than by calling a constructor accepting a raw pointer to the resource as a parameter.

What is the use of std :: make_unique?

In this case, std::make_unique provides a "Basic Exception Safety" that the memory allocated and object created by new will never be orphaned no matter what.

Can you delete a unique pointer?

An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.

Where is make_unique defined?

Defined in header <memory> template< class T, class... Args > unique_ptr<T> make_unique( Args&&...


2 Answers

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.

like image 142
Kerrek SB Avatar answered Sep 28 '22 21:09

Kerrek SB


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 
like image 44
Jon Ringle Avatar answered Sep 28 '22 22:09

Jon Ringle