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

问题描述

我最近一直在搞混C ++中的事件系统,例如boost :: signals2和类似的库。它们似乎都有一个共同的局限性:它们实际上与移动语义无关。

如果将信号连接到作为对象成员的插槽,则它引用该对象的当前内存地址以调用该插槽。一旦该地址发生更改(例如,由于对象所在的std :: vector必须重新分配其内存数组),连接就会中断。它仍然指的是移出的地址。

对于如何正确使用此类信号/插槽库,我有些困惑。您是否真的需要确保插槽永远不会更改其位置,例如将其放置在堆上?还是有一种方法可以使信号自动知道已更改的插槽位置?

解决方法

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

以下是升压信号2信号用法的简单示例:

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类或更改它们在运行时,这不会影响连接。 您唯一需要注意的是对象的寿命:删除对象之前必须断开插槽。否则,在调用信号时,object.member_func();调用会导致未定义行为,因为该对象不再存在。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...