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

Posted

技术标签:

【中文标题】如何将非静态成员函数作为unique_ptr删除器传递[重复]【英文标题】:How to pass a non-static member function as a unique_ptr deleter [duplicate] 【发布时间】:2015-04-08 21:07:01 【问题描述】:
#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&lt;CURL, void (*)(CURL *)&gt;'

在我看来,deleter 模板参数的声明是正确的。它是一个返回 void 并将 CURL * 作为参数的函数指针。这与del_curl 的签名相匹配。

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

【问题讨论】:

void del_curl(CURL * ptr_curl);从非静态成员函数更改为静态成员函数。 @FranciscoAguilera 因为您试图将指向函数的指针绑定到指向成员函数的指针,但这不起作用:uptr_curl_(init_curl(), &amp;client::del_curl) @FranciscoAguilera 因为您的陈述“这与 del_curl 的签名相匹配”是错误的。它确实 not 匹配。 void (*)(CURL*)void (client::*)(CURL*) 不同。一个是会员(需要this),另一个不是。 它们不是同一类型。你可以全大写为什么你想要的;但这就是为什么,不管你喜不喜欢。 @vsoftco 是的,它应该以某种方式工作,因为我不希望那些是静态函数。它们不是静态的。对于client 的所有实例,没有1 个大curl_init,它们对于每个客户端都是唯一的。 不,它确实不匹配,并且您的问题中没有任何内容与模板实际相关。指向函数的指针不能指向指向成员函数的指针,这在模板之外也是不可能的,而且从根本上来说是不可能的。花点时间想想它是如何工作的。您需要一些实例来调用非静态成员函数。您没有任何可用的实例来调用它,也没有任何空间来跟踪实例。所以你不能调用它。我很确定这已经被问过了。让我看看我能不能找到一个好的副本。 【参考方案1】:

@R 的回答。 Sahu是正确的imo。但是,如果您坚持传递非静态成员函数删除器,这里有一种使用旧的 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);
               
          )

【讨论】:

您是对的,这是正确的,对于您想要“将静态成员函数作为 unique_ptr 删除器传递”的情况,但我的问题是“如何将非静态成员函数作为unique_ptr 删除器”。 上升了。我正要发布完全相同的代码。谢谢你省了我的麻烦。 =P @FranciscoAguilera deleter 这里是非静态的。 @vsoftco 是的,相同的 lambda 并不等同于相同的闭包,所以我同意您对难度的评估。自定义删除器包装器(您的绑定正在有效地执行)似乎是最好的选择。你可以在没有std::bind 的情况下通过自己提供完整的monte (see example) 来做到这一点,但是当你可以绑定它时为什么还要麻烦呢。 @FranciscoAguilera unique_ptr 构造函数中的第二个参数将尝试转换为第二个模板,在这种情况下,std::function 允许转换任何可调用对象(包括 lambda) 【参考方案2】:

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

&amp;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))

   // ...

【讨论】:

确实,我认为是否可以使用非静态成员函数作为删除器也很有趣。你能以某种方式使用std::function 吗? 不,你错了。 client::del_curl 的类型是 void (psclient::*)(void *)。查看我的编辑。 您不能将非静态成员函数作为删除器参数传递还有另一个原因,我想知道为什么。 @vsoftco 那是最初的问题。没有人会读到最后。 xD @FranciscoAguilera,这是声明还是预感? @RSahu 因为我看不出有什么理由需要这样做,所以我想为该类初始化一个 curl 实例,也就是成员函数,而不是所有实例,也就是静态的。跨度>

以上是关于如何将非静态成员函数作为unique_ptr删除器传递[重复]的主要内容,如果未能解决你的问题,请参考以下文章

将非静态成员函数作为参数传递给另一个类中的成员函数

如何在构造函数中使用删除器初始化 std::unique_ptr?

如何在静态方法中取消分配使用std :: memory_resource分配的内存而不更改下面的函数签名

具有右值删除器的 unique_ptr 构造函数返回 null?

如何将 unique_ptr 对象作为参数传递给作为库的类

如何在构造函数中为成员 unique_ptr 赋予默认值? [复制]