5

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?
wl2776
  • 4,099
  • 4
  • 35
  • 77
  • 1
    Define your own function `std::unique_ptr make_resource() { return std::unique_ptr(resource_new(), resource_delete); }`? [Example](http://codereview.stackexchange.com/questions/4679/shared-ptr-and-file-for-wrapping-cstdio-update-also-dlfcn-h) – Kerrek SB Sep 21 '15 at 15:47
  • possible duplicate of [std::unique\_ptr, deleters and the Win32 API](http://stackoverflow.com/questions/14841396/stdunique-ptr-deleters-and-the-win32-api) – legends2k Sep 21 '15 at 15:59

3 Answers3

6

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() };
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
1

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

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.

wl2776
  • 4,099
  • 4
  • 35
  • 77