Efficient user memory debiter for std :: unique_ptr?

This may be a little implementation specific, but some of them seem fundamental.

I am sure that I should skip something in the standard library.

The problem is this:

I want to implement a std::unique_ptr whose deleter free()

[because value is allocated through malloc() ]

There are, of course, many options for how to do this, but (at least in g ++ 4.8.4 for x86-64) they apparently have different consequences of using memory.

etc .: Method 1:

 std::unique_ptr<char, std::function<void(void*)>> ptr_a(malloc(10), free); 

However, sizeof(ptr_a) == 40 bytes (8 for void *, 32 for std :: function <>)

Method 2:

 std::unique_ptr<void, void (*)(void*)> ptr_b(malloc(10), free); 

Somewhat better, since sizeof(ptr_b) == 16 bytes (8 for void *, 8 for a pointer to a useful function])

Method 3:

 template <void (*T)(void*)> class Caller { public: void operator()(void* arg) { return T(arg); } }; std::unique_ptr<void, Caller<free>> ptr_c(malloc(10));` 

At this point, sizeof(ptr_c) == 8 bytes (the smallest possible), but I had to introduce a class that was a pretty clean template (and, as shown, easily templatized).

It looks like such a simple template - is there any element in the STL that does what Caller<> does above?

Of course, g ++ does indeed call free () by default when calling delete on a trivial type - but this seems far from guaranteed by the standard (if nothing else, the new / delete can be overridden from the default distribution / deallocation of the function, and default_delete will then cause the delete to be replaced) .

And plus, there are other cases where the release of an object allocated in the pure-C library will be implemented by a simple function call, rather than by deleting. It seems somewhat tedious that you need to wrap such distribution / release functions in classes in order to get std :: unique_ptr to call them both correctly and efficiently - which makes me think that I'm missing something (most of the other modern C ++ specifications seems very well thought out).

+5
source share
2 answers

C ++ 11 is of type integral_constant , which works with things that are not integers. In C ++ 14, a constexpr value is returned.

So in C ++ 14 we can do:

 std::unique_ptr<void, std::integral_constant<decltype(free)*, free>> ptr_c(malloc(10)); 

It is not comfortable. (It depends on what () considers the cast-to-function pointer on the left side argument).

We can make code without code:

 using default_free = std::integral_constant<decltype(free)*, free>; std::unique_ptr<void, default_free> ptr_c(malloc(10)); 

to get rid of some noise at the place of use.

In C ++ 17, we can write an assistant:

 template<auto t> using val = std::integral_constant< std::decay_t<decltype(t)>, t >; 

gives us:

 std::unique_ptr<void, val<free>> ptr_c(malloc(10)); 

which is cleaner in my opinion.

Live examples .

We can write our own version in C ++ 11:

 template<class T, std::decay_t<T> t> struct val { constexpr operator T() noexcept const { return t; } }; using default_free = val<decltype(free), free>; std::unique_ptr<void, default_free> ptr_c(malloc(10)); 
+5
source

There is also a 4th use case for an idle lambda:

 auto free_lmbd = [](void *_ptr) { free (_ptr);}; std::unique_ptr<void, decltype (free_lmbd)> ptr {malloc(10), free_lmbd}; 

which will also have 8 bytes (at least on my computer), just like your third option.

I recommend reading http://www.bfilipek.com/2016/04/custom-deleters-for-c-smart-pointers.html

0
source

Source: https://habr.com/ru/post/1270250/


All Articles