使用typedef为std::unique_ptr指定自定义默认删除器

Specifying custom default deleter for std::unique_ptr with typedef

本文关键字:自定义 默认 删除 typedef std unique 使用 ptr      更新时间:2023-10-16

我有一个C代码,与一些资源的工作。它有像

这样的函数
ResourcePointer resource_new(void);
void resource_delete(ResourcePointer *res);

其中ResourcePointer

typedef void * ResourcePointer;

我想为std::unique_ptr创建一个typedef,指定自定义默认删除器。

下面的工作,但需要重复resource_delete

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

和后面的代码

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

我应该如何改变typedef,以便编译器每次需要时自动替换resource_delete ?我希望我的代码看起来像下面的

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

编译器应该以某种方式猜测它应该为每个类型为Resource_auto_pointer2的对象调用resource_delete

我在MS Visual Studio 2013中工作。

我读过其他类似问题的答案。有两件事我不明白。

  1. 为什么std::函数不工作?
  2. 为什么我要创建新的类型,既然(大概)一切都已经说了?

定义一个调用正确函数的函数对象:

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>;
现在您不需要将deleter传递给unique_ptr构造函数,因为deleter可以默认构造,并且会做正确的事情:
res_ptr p{ resource_new() };

在未求值的上下文中使用lambda,包括c++ 20 lambda:

#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;
}

我找到了我问题的答案。std::unique_ptr需要实例化类型,而resource_delete函数的地址是常量。需要创建structclass来将其转换为type