0

我想为向插槽发出信号的模块(线程)创建 boost::signals2 的包装类。即,一个模块应该通过从我的 Signal 类继承来获得典型的简单信号功能(例如公共 connect(...) 方法)。我还想隐藏使用的实际信号槽实现。

具体插槽继承自通用插槽基类,该基类具有定义其签名的模板参数。插槽只是具有合适签名的函子。

这个问题与这个问题有些相关。插槽存储为 shared_ptr 并且需要生命周期管理。即,只要信号本身退出,Signal 类就应该持有对插槽的引用以使其保持活动状态。因此我无法连接 std::functions 或类似的。我必须连接插槽基类的 shared_ptrs 。

我目前的方法,到目前为止没有线程安全(MSVC 2010):

template<class FunSig>
class Slot;

template<class R>
class Slot<R()>
{
public:
    typedef R Ret_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()() = 0;
};

template<class R, class A1>
class Slot<R(A1)>
{
public:
    typedef R Ret_type;
    typedef A1 Arg1_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()(Arg1_type) = 0;
};

// and so forth for more arguments


/*
Signalling class.
This class is basically a wrapper for the boost::signals2 class with 
lifetime management for slots.
Slots are connected by a shared_ptr which gets stored
in a std::vector to ensure that a slot exists at least as long as the signal.
*/
template<class FunSig>
class Signal
{
public:
    typedef Slot<FunSig> Slot_type;
    typedef boost::signals2::signal<FunSig> BoostSignal;
    typedef typename BoostSignal::slot_type BoostSlot;

public:
    virtual ~Signal() {}

    void connectSlot(std::shared_ptr<Slot_type> slot_ptr);

protected:
    //void emitSignal( ... );
    //void disconnectAllSlots();

private:
    BoostSignal sig_;

    /// vector of shared_ptr to slots for lifetime management
    std::vector<std::shared_ptr<Slot_type> > slotsVec_;
};


template<class FunSig>
void Signal<FunSig>::connectSlot(std::shared_ptr<Slot_type> slot_ptr)
{
    sig_.connect(*slot_ptr); // version A: compiler error

    // OR

    sig_.connect(boost::ref(*slot_ptr)); // version B: warning, but compiles and runs


    // add slot pointer to vector of slots
    slotsVec_.push_back(slot_ptr);
}

此代码(版本 A)无法编译。它打破了 boosts slot_template.hpp 和 connectSlot 方法中标记的行:

error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const Slot<FunSig>' (or there is no acceptable conversion)
1>          with
1>          [
1>              FunSig=void (const float &)

有趣的是,如果使用版本 B,则此代码将编译并运行 - 即通过插槽传递 boost::ref。虽然有一个编译器警告“带有可能不安全的参数的函数调用 - 此调用依赖于调用者来检查传递的值是否正确。” 在 boost 的 singals2 auto_buffer.hpp 中。

那么这里的实际问题是什么以及如何解决呢?为什么这适用于 boost::ref 以及为什么没有它就无法编译?

我什至不确定整个设计理念是否有用。最初的想法是将整个信令/插槽的东西隐藏在一个超类中,并专注于签名(并包括生命周期管理)。

关于 boost 的信号 2 的另一个问题:singals2 connect() 方法引用了一个插槽。这在内部是如何处理的。它是使用连接插槽的引用还是复制插槽?这很重要,因为我的插槽处理动态分配的内存。

4

2 回答 2

1

我假设您的意思是警告 C4996。这是 Microsoft 的 c++ 标准库实现的一个功能,它会在标准算法使用潜在不安全参数编译时向您发出警告,例如,在此代码段中,调用者负责足够大小的sourceand target

int source[3] = { 1, 2, 3 };
int target[3];
std::copy(source, source + 3, target);

您不应该重复 Boost.Signals2 已经提供的功能:该库提供了对连接到信号的“插槽”的复杂生命周期管理。通读文档,他们预见到对这方面的非常精细的控制。此外,您失去了一个非常有趣的功能 - Boost.Signals2 的线程安全:您需要管理线程安全插入和删除slotVec_自己,这是一项不平凡的工作......

我自己正在研究一个类似的抽象库,称为vex,看看abstract_multicast_delegateabstract_signalin vex/functional/contracts。基于的实现signals2::signal可以在 中找到vex/functional/implementation/bs2_signal.h。然而,这仍然是一个游乐场,我也在尝试替代实现......

编辑:对不起,我不知道如何指向 codeplex 的 hg 存储库的尖端。我不得不删除链接,因为自昨天以来发生了很多变化......

于 2013-04-27T10:59:43.837 回答
0

这个问题已经在不同的上下文中得到了回答

实际上 std::ref 或 boost::ref 必须使用,因为 boost::signals2 connect 方法复制了它的参数。但是类 Slot 是不可复制的,因为它是一个抽象类。因此使用 boost::ref 是推荐的解决方案,因为它使插槽可复制。

于 2013-05-02T08:28:29.967 回答