Обертка для Boost :: сигналов2 с управлением временем жизни для общих слотов

Я хотел бы создать класс-оболочку для boost :: signal2 для модулей (потоков), который излучает сигналы в слоты. То есть модуль должен получить типичные возможности простой сигнализации (например, метод public connect (…)) путем наследования от моего класса Signal. Я также хотел бы скрыть фактическую реализацию сигнального слота, которая используется.

Конкретный слот наследуется от базового базового класса Slot, у которого есть параметр шаблона, определяющий его сигнатуру. Слот — это просто функтор с подходящей подписью.

Этот вопрос несколько связан с этот вопрос. Слоты хранятся как 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) не компилируется. Он разрывается внутри Boots 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 — т.е. передается повышение :: ref слота. Хотя есть предупреждение компилятора «Вызов функции с параметрами, которые могут быть небезопасными — этот вызов полагается вызывающей стороне на проверку правильности переданных значений». в бустах singals2 auto_buffer.hpp.

Так в чем же заключается проблема и как ее решить? Почему это работает с boost :: ref и почему он не компилируется без него?

Я даже не уверен, что вся идея дизайна полезна. Первоначальная идея заключалась в том, чтобы спрятать всю сигнализацию / слот в суперклассе и сосредоточиться на сигнатуре (и включить управление временем жизни).

Дополнительный вопрос относительно сигналов boost2: метод singals2 connect () берет ссылку на слот. Как это обрабатывается внутри. Использует ли он ссылку на подключенный слот или делает копию слота? Это важно, так как мои слоты обрабатывают динамически распределенную память.

0

Решение

Я полагаю, вы имеете в виду предупреждение C4996. Это особенность реализации стандартной библиотеки Microsoft c ++, которая предупреждает вас всякий раз, когда стандартный алгоритм компилируется с потенциально небезопасными аргументами, например, в этом фрагменте вызывающая сторона отвечает за достаточные размеры source а также target:

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

Вы не должны дублировать функциональность, уже предоставленную Boost.Signals2: библиотека обеспечивает сложное управление на протяжении всей жизни «слотами», подключенными к сигналу. Прочитайте документы, они предусматривают очень тонко-гранулированный контроль этого аспекта. Кроме того, вы потеряете очень интересную функцию — безопасность потоков в Boost.Signals2: вам нужно будет управлять безопасными для потоков вставками и удалениями в и из slotVec_ себя, что является нетривиальным предприятием …

Я работаю над подобной библиотекой абстракций под названием сердить сам, посмотри на abstract_multicast_delegate а также abstract_signal в vex/functional/contracts, Реализация на основе signals2::signal можно найти в vex/functional/implementation/bs2_signal.h, Это все еще игровая площадка, я тоже экспериментирую с альтернативными реализациями …

РЕДАКТИРОВАТЬ: Извините, я не знаю, как указать на верхушку репозитория hg в codeplex. Мне пришлось удалить ссылки, так как многое изменилось со вчерашнего дня …

1

Другие решения

На этот вопрос ответили в другом контексте Вот.

На самом деле нужно использовать std :: ref или boost :: ref, потому что метод boost :: signal2 connect копирует свои аргументы. Но класс Slot не подлежит копированию, поскольку это абстрактный класс. Следовательно, использование boost :: ref является рекомендуемым решением, поскольку оно делает слот копируемым.

0

По вопросам рекламы [email protected]