c++ - 使用 std::function 和 std::bind 来存储回调和处理对象删除。

标签 c++ c++11 std-function stdbind

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

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

以下似乎有效:

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

要使用它:

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

但是上面给出了错误:

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

是否有更好的方法来做到这一点,或者是否有更好的方法让它发挥作用?

我注意到一些有趣的事情。如果我使用 std::shared_ptr,则 use_count() 会随着原始代码中对 std::bind 的调用而递增。因此,我无法手动重置/销毁对象,除非我取消设置我的经理的成员。这种行为记录在哪里,我通常使用 cppreference

我查看了以下问题,但似乎无法解决我的问题:How can I use polymorphism with std::function?

最佳答案

模板 setFunction 以便您可以接受指向派生成员的指针,而不必为 cv/ref 限定符的组合编写 12 个重载。

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

显然,在调用 m_function.second 之前,您需要确保 lock() 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).*member)(d);
        }
        else {
             // handle pointer no longer valid case.
        }
    };
}

关于c++ - 使用 std::function 和 std::bind 来存储回调和处理对象删除。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34397819/

相关文章:

c++ - std::functions 错误 vector

c++ - <functional> 中奇怪的模板语法

c++ - 在 C++ 中如何将字符串转换为类对象?

c++ - header 在 C++ 中包含 Creep

c++ - 空类和空函数的大小?

c++ - 奇怪的 std::wregex 行为

c++ - 编织链表元素的转轮技术

c++ - 迭代器元组。运算符++的实现

c++ - 自定义模板编程

c++ - 将lambda函数存储到std::function中有什么好处?