Reputation: 4327
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.
Upvotes: 5
Views: 687
Reputation: 44
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;
}
Upvotes: 1
Reputation: 4327
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.
Upvotes: 0
Reputation: 171303
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() };
Upvotes: 6