Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a non-static member function as a unique_ptr deleter [duplicate]

Tags:

c++

unique-ptr

#include <memory>
#include <iostream>
#include <exception>
#include <curl/curl.h>

class client
{
private:
    std::unique_ptr<CURL, decltype(&psclient::del_curl)> uptr_curl_;

    inline CURL * init_curl()
    {
        CURLcode result = curl_global_init(CURL_GLOBAL_DEFAULT);
        if(result != CURLE_OK)
            throw std::logic_error(curl_easy_strerror(result));
        return curl_easy_init();
    }

    inline void del_curl(CURL * ptr_curl)
    {
        curl_easy_cleanup(ptr_curl);
        curl_global_cleanup();
    }
public:
    inline client()
    : uptr_curl_(init_curl(), &client::del_curl)
    {
    }
}

The compiler keeps complaining No matching constructor for initialization of 'std::unique_ptr<CURL, void (*)(CURL *)>'

It seems to me like the declaration is correct for the deleter template argument. It is a function pointer that returns void and takes a CURL * as an argument. This matches the signature of del_curl.

Is there yet another random rule, unknown to me, in C++ that specifies a requirement for template arguments to non-static member function pointers? If so, why?

like image 683
Francisco Aguilera Avatar asked Apr 08 '15 21:04

Francisco Aguilera


2 Answers

The answer of @R. Sahu is correct imo. However, if you insist of passing a non-static member function deleter, here is a way of doing it using the good old std::bind and std::function:

#include <memory>
#include <iostream>
#include <functional>

class Foo
{
private:
    std::unique_ptr<int, std::function<void(int*)>> _up;
public:
    Foo(): _up(new int[42], std::bind(&Foo::deleter, this, std::placeholders::_1))
    {

    }
    void deleter(int* p)
    {
        delete[] p;
        std::cout << "In deleter" << std::endl;
    }
};

int main()
{
    Foo foo;
}

PS: I just don't like the bind, I wonder if one can improve on that.


With a lambda:

Foo(): _up(new int[42],
               [this](int* p)->void
               {
                   deleter(p);
               }
          ){}
like image 138
vsoftco Avatar answered Nov 15 '22 04:11

vsoftco


The second template parameter used in the declaration of uptr_curl_ is void (*)(CURL *)

The type of &client::del_curl is void (CURL::*)(CURL*).

They are not the same. You can change del_curl to a static member function. That will resolve the problem.

Update

You can use a non-static member function with the help of std::function and std::bind.

class client
{
   public:
      client();
   private:
      std::unique_ptr<CURL, std::function<void(CURL *)>> uptr_curl_;
      CURL * init_curl();
      void del_curl(CURL * ptr_curl);
};

client::client() : uptr_curl_(init_curl(),
                              std::bind(&client::del_curl, this, std::placeholders::_1))
{
   // ...
}
like image 24
R Sahu Avatar answered Nov 15 '22 03:11

R Sahu