使用std :: function和std :: bind来存储回调和处理对象删除。 [英] Using std::function and std::bind to store callback and handle object deletion.

查看:746
本文介绍了使用std :: function和std :: bind来存储回调和处理对象删除。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个管理器,使用C ++ 11存储多态类的成员函数的回调。问题是,我不知道如何处理的情况下,该成员属于的对象被删除或应删除,我想让界面尽可能简单。



所以我想到了以下内容:将 std :: weak_ptr 存储到对象以及 std :: function 给成员。



以下似乎有效:

  class MyBase {
public:
MyBase(){}
virtual〜MyBase(){}
};
// -------------------------------------------- ------

class MyClass:public MyBase {
public:
MyClass():MyBase(){}
void myDouble {std :: cout< 价值是:< val<< std :: endl; }
};
// -------------------------------------------- ------

类管理器{
public:
void setFunction(std :: weak_ptr< MyBase> base,std :: function< void(double)> func){
m_function.first = base;
m_function.second = func;
}
private:
std :: pair< std :: weak_ptr< MyBase>,std :: function< void(double)> m_function;
};

使用:

  Manager db; 
std :: shared_ptr< MyClass> myClass = std :: make_shared< MyClass>();
db.setFunction(myClass,std :: bind(& MyClass :: myDouble,myClass,std :: placeholders :: _ 1));

现在我想隐藏 std :: bind 部分,所以他只需要调用:

  db.setFunction(myClass,& MyClass :: myDouble); 

所以我想在我的经理功能中得到几乎以下的工作:

  void setFunc2(std :: weak_ptr< MyBase> base,std :: function< void(double)> func){
m_function.first = base;
m_function.second = std :: bind(func,base,std :: placeholders :: _ 1);
}

但上述错误:

 错误:不匹配'operator ='(操作数类型为'std :: function< void(double)>'和
'std :: _ Bind_helper< ; false,std :: function< void(double)>& std :: weak_ptr< MyBase>& const std :: _ placeholder< 1>&> :: type {aka std :: _ Bind< std :: function< void(double)>(std :: weak_ptr< MyBase> std :: _ Placeholder< 1>)>}')
m_function.second = std :: bind(func,base,std :: placeholder :: _ 1);

有更好的方法来做到这一点, >

我注意到有趣的东西。如果我使用 std :: shared_ptr use_count() std :: bind 。因此,我不能手动重置/销毁对象,除非我取消了我的经理的成员。此行为记录在哪里,我通常使用 cppreference



我看了下面的问题,但似乎不能得到它的工作对我的问题:如何使用多态与std :: function?

code> setFunction ,以便您可以接受指向成员的派生,并且不必为cv / ref限定符的组合写入12个重载。

 模板<类D,类D2,类F> 
void setFunction(const std :: shared_ptr< D& sp,F D2 :: * member){
//可选static_assert,D2是D的基础。
m_function.first = sp;
m_function.second = std :: bind(member,sp.get(),std :: placeholders :: _ 1);
}

显然你需要确保你 lock在调用 m_function.second 之前 m_function.first



或者,只需使用捕获 weak_ptr 和成员函数指针的lambda:

  std :: function< void(double)> m_function; 

template< class D,class D2,class F>
void setFunction(const std :: shared_ptr< D& sp,F D2 :: * member){
std :: weak_ptr< D& wp = sp;
m_function = [wp,member](double d){
if(auto sp = wp.lock()){
((* sp)。
}
else {
//句柄指针不再有效的情况。
}
};
}


I want to implement a manager that stores callbacks to member functions of polymorphic classes using C++11. The issue is that I am not sure how to handle the case where the object that the member belongs to gets deleted or should be deleted and I want to make the interface as simple as possible.

So I thought of the following: Store a std::weak_ptr to the object as well as a std::function to the member.

The following seems to work:

class MyBase {
public:
    MyBase() {}
    virtual ~MyBase() {}
};
//--------------------------------------------------

class MyClass : public MyBase {
public:
    MyClass() : MyBase() {}
    void myDouble(double val) const { std::cout << "Value is: " << val << std::endl; }
};
//--------------------------------------------------

Class Manager {
public:
    void setFunction(std::weak_ptr<MyBase> base, std::function<void(double)> func) {
        m_function.first  = base;
        m_function.second = func;
    }
private:
    std::pair<std::weak_ptr<MyBase>, std::function<void(double)>> m_function;
};

To use this:

Manager db;
std::shared_ptr<MyClass> myClass = std::make_shared<MyClass>();
db.setFunction(myClass, std::bind(&MyClass::myDouble, myClass, std::placeholders::_1));

Now I want to hide the std::bind part from the user, so that he only needs to call:

db.setFunction(myClass, &MyClass::myDouble);

So I want to get almost the following working in my manager function:

void setFunc2(std::weak_ptr<MyBase> base, std::function<void(double)> func) {
    m_function.first  = base;
    m_function.second = std::bind(func, base, std::placeholders::_1);
}

But the above gives errors:

error: no match for 'operator=' (operand types are 'std::function<void(double)>' and 
'std::_Bind_helper<false, std::function<void(double)>&, std::weak_ptr<MyBase>&, const std::_Placeholder<1>&>::type {aka std::_Bind<std::function<void(double)>(std::weak_ptr<MyBase>, std::_Placeholder<1>)>}')
         m_function.second = std::bind(func, base, std::placeholders::_1);

Is there a better way to do this, or perhaps a way to get this working?

Something interesting that I notice. If I use the std::shared_ptr the use_count() gets incremented with the call to std::bind in the original code. Thus I can not manually reset/destroy the object unless I unset the member on my manager. Where is this behaviour documented, I normally use cppreference?

I have looked at the following question but can't seem to get it working for my problem: How can I use polymorphism with std::function?

解决方案

Template setFunction so that you can accept pointer-to-member-of-derived, and don't have to write 12 overloads for the combinations of cv/ref qualifiers.

template<class D, class D2, class F>
void setFunction(const std::shared_ptr<D> &sp, F D2::* member) {
    // optionally static_assert that D2 is a base of D.
    m_function.first  = sp;
    m_function.second = std::bind(member, sp.get(), std::placeholders::_1);
}

Obviously you need to make sure you lock() m_function.first before calling m_function.second.

Alternatively, just use a lambda that captures both the weak_ptr and the member function pointer:

std::function<void(double)> m_function;

template<class D, class D2, class F>
void setFunction(const std::shared_ptr<D> &sp, F D2::* member) {
    std::weak_ptr<D> wp = sp;
    m_function = [wp, member](double d) {
        if(auto sp = wp.lock()){
             ((*sp).*member)(d);
        }
        else {
             // handle pointer no longer valid case.
        }
    };
}

这篇关于使用std :: function和std :: bind来存储回调和处理对象删除。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆