如何将非静态成员函数作为 unique_ptr 删除器传递

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

#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)
    {
    }
}

编译器一直报错No matching constructor for initialization of 'std::unique_ptr<CURL, void (*)(CURL *)>'

在我看来,删除模板参数的声明是正确的。它是一个 returns 无效的函数指针,并以 CURL * 作为参数。这与 del_curl.

的签名匹配

在 C++ 中是否还有另一个我不知道的随机规则指定了对非静态成员函数指针的模板参数的要求?如果是,为什么?

uptr_curl_声明中使用的第二个模板参数是void (*)(CURL *)

&client::del_curl的类型是void (CURL::*)(CURL*)

它们不一样。您可以将 del_curl 更改为 static 成员函数。这将解决问题。

更新

您可以在 std::functionstd::bind 的帮助下使用非 static 成员函数。

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))
{
   // ...
}

@R的回答。萨胡是正确的我。但是,如果您坚持要传递一个非静态成员函数删除器,这里有一种方法可以使用旧的 std::bindstd::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:我就是不喜欢 bind,我想知道是否有人可以改进它。


使用 lambda:

Foo(): _up(new int[42],
               [this](int* p)->void
               {
                   deleter(p);
               }
          ){}