C++ 中的事件系统和移动语义

Event System and Move Semantics in C++

我最近一直在研究 C++ 中的事件系统,例如 boost::signals2 和类似的库。它们似乎都有一个共同的局限性:它们并不真正适用于移动语义。

如果将信号连接到作为对象成员的插槽,它会引用该对象的当前内存地址来调用插槽。一旦该地址发生变化,例如因为对象所在的 std::vector 必须重新分配它的内存数组,连接就会中断。还是指搬出地址

我对如何正确使用此类 signal/slot 库有些困惑。你真的只需要确保插槽永远不会改变它的位置,例如将它放在堆上吗?或者有没有办法让信号自动知道插槽位置的变化?

问题是插槽在内存中的位置不依赖于实例数据。成员函数作为 class 所有实例的单一定义存在于内存中,并且不会更改其位置。当您为特定对象(如 object->member_func())调用函数时,“this”指针与其他参数隐式传递,因此该函数知道调用了哪个对象。 https://www.tutorialspoint.com/cplusplus/cpp_this_pointer.htm

这里是 boost signals2 信号用法的一个简单示例:

class Handler
{
private:
    std::vector<std::string> array;
public:
    void member_func(int value) {}
};

#include <boost/signals2.hpp>    
void test()
{
    boost::signals2::signal<void(int)> signal;
    Handler object;
    signal.connect(std::bind( &Handler::member_func, &object, std::placeholders::_1 ));
    signal(5);
}

我们在绑定方法 args 中传递指向对象 (&object) 的指针,因此当信号被调用时,boost 将调用 object.member_func(); 如果您向 Handler 添加任何数据成员 class 或在运行时更改它们,这不会影响连接。 这里你唯一需要关心的是对象的生命周期:你必须在删除对象之前断开插槽。否则,当调用信号时,object.member_func(); 调用会导致未定义的行为,因为该对象不再存在。