简体   繁体   中英

Specifying custom default deleter for std::unique_ptr with typedef

I've got a C code, working with some resources. It has functions like

ResourcePointer resource_new(void);
void resource_delete(ResourcePointer *res);

where ResourcePointer is

typedef void * ResourcePointer;

I would like to create a typedef for std::unique_ptr , specifying that custom default deleter.

The following works, but requires repeating resource_delete .

typedef std::unique_ptr<std::remove_pointer<ResourcePointer>::type, 
                            void(*)(ResourcePointer)> Resource_auto_pointer;

and later in the code

Resource_auto_pointer resource(resource_new(), resource_delete);
...
Resource_auto_pointer res2 = { resource_new(), resource_delete };

How should I change typedef , so that compiler would automatically substitute resource_delete every time it is needed? I want my code to look like the following

Resource_auto_pointer2 resource (resource_new());
...
Resource_auto_pointer2 res2 = { resource_new() };

The compiler should somehow guess that it should call resource_delete for each object of type Resource_auto_pointer2 .

I work in MS Visual Studio 2013.

Update I've read answers to other similar questions. I don't understand two things.

  1. Why std::function doesn't work?
  2. why should I create new types, since (presumably) everything is said already?

Define a function object that calls the right function:

struct resource_deleter
{
  using pointer = std::remove_pointer<ResourcePointer>::type;
  void operator()(ResourcePointer p) const { resource_delete(p); }
};

using res_ptr = std::unique_ptr<resource_deleter::pointer, resource_deleter>;

Now you don't need to pass the deleter to the unique_ptr constructor, because the deleter can be default-constructed and will do the right thing:

res_ptr p{ resource_new() };

I've found an answer to my question. std::unique_ptr requires types in instantiation, while address of resource_delete function is a constant. One needs to create a struct or a class to convert it to type.

Using lambdas, including C++20 lambda in unevaluated context:

#include <iostream>
#include <memory>
#include <type_traits>

using HANDLE = std::byte*;

HANDLE make_HANDLE() { static auto k_h = HANDLE{}; return ++k_h; } // AKA Win32's CreateFile etc
void close_HANDLE(HANDLE h) { std::cout << "HANDLE_close(" << h << ")" << std::endl; } // AKA Win32's CloseHandle etc

#if __cplusplus >= 202002 // C++20; using lambda in unevaluated context
using HANDLE_ptr = std::unique_ptr<
    std::remove_pointer_t<HANDLE>,
    decltype([](HANDLE h) { close_HANDLE(h); })>;
#else
[[maybe_unused]] inline static auto HANDLE_deleter = [](HANDLE h) { close_HANDLE(h); };
using HANDLE_ptr = std::unique_ptr<std::remove_pointer_t<HANDLE>, decltype(HANDLE_deleter)>;
#endif

int main()
{
    auto h1 = HANDLE_ptr(make_HANDLE());
    auto h2 = HANDLE_ptr(make_HANDLE());
    auto h3 = HANDLE_ptr(make_HANDLE());
    std::cout << h1 << std::endl;
    std::cout << h2 << std::endl;
    std::cout << h3 << std::endl;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM