Russian Qt Forum
Апрель 28, 2024, 01:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6 ... 8   Вниз
  Печать  
Автор Тема: Частный случай механизма сигнал-слот  (Прочитано 71839 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #45 : Февраль 25, 2011, 13:42 »

Выявил тут один баг, когда внедрял эту штуку в програмку..
Вобщем возникала проблема, при использовании типа void
Код
C++ (Qt)
class A
{
public:
   ssc::signal<void> sig;
};
 
Сигнал sig - соединяется с функциями которые возвращают T_return и не имеют аргументов:
Код
C++ (Qt)
class B : public ssc::trackable
{
public:
   int slot() const {   // Вот например с такой функцией
       return 123;
   }
};
 

Сейчас проблема решена с помощью специализации шаблонов на тип void..
Кстати, такой приём в стандартной библиотеке применён и для std::vector<bool>  

Исходники прилагаются
« Последнее редактирование: Февраль 25, 2011, 15:36 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #46 : Февраль 25, 2011, 18:37 »

Млин! Ещё одна опечатка выявилась, которая приводит к утечке :
В файле smart_ptr.h в методе try_destroy():
Код
C++ (Qt)
template <class T>
inline void smart_ptr<T>::try_destroy()
{
   if (!_obj)
       return;
 
   if ((*_counter) == 1) {
       delete _counter;
       _counter = 0;
       delete _obj;
       _obj = 0;
   }
}
 
Забыл уменьшить счётчик _counter
Правильно так:
Код
C++ (Qt)
template <class T>
inline void smart_ptr<T>::try_destroy()
{
   if (!_obj)
       return;
 
   if ((*_counter)-- == 1) {
       delete _counter;
       _counter = 0;
       delete _obj;
       _obj = 0;
   }
}
 

Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #47 : Февраль 26, 2011, 04:25 »

Изменил архитектуру ssc
Теперь сигнал может принимать два аргумента и связываться с функциями вида:
Код
C++ (Qt)
// не методы класса
T_return (*fun_type)(T_arg1, T_arg2);
T_return (*fun_type)(T_arg1);
T_return (*fun_type)();
 
// методы класса
T_return (T_receiver::*mem_fun_type)(T_arg1, T_arg2);
T_return (T_receiver::*const_mem_fun_type)(T_arg1, T_arg2) const;
T_return (T_receiver::*mem_fun_type)(T_arg1);
T_return (T_receiver::*const_mem_fun_type)(T_arg1) const;
T_return (T_receiver::*mem_fun_type)();
T_return (T_receiver::*const_mem_fun_type)() const;
 


Сам интерфейс практически не изменился, пример:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
void func(const std::string &str) {
   std::cout << "func slot: " << str << std::endl;
}
 
class A
{
public:
   A() {
       std::cout << "A()" << std::endl;
   }
   ~A() {
       std::cout << "~A()" << std::endl;
   }
 
   ssc::signal<const std::string &> sig_fun;  /* теперь нужно тип аргумента расписывать подробно!
                                                                      И чтоб он в точности соответствовал арг. слота  */

   ssc::signal<int> sig_1;
   ssc::signal<const std::string &, int> sig_2;
 
   void run() const {
       sig_fun("Hello!");
       sig_1(2011);
       sig_2("Hello World!", 1234567);
   }
};
 
class B : public ssc::trackable
{
public:
   B() {
       std::cout << "B()" << std::endl;
   }
   ~B() {
       std::cout << "~B()" << std::endl;
   }
 
   void slot1(int x) const {
       std::cout << "slot1: x = " << x << std::endl;
   }
   int slot2(const std::string &str, int x) const {
       std::cout << "slot2: " << str << "  x = " << x << std::endl;
       return 67;
   }
};
 
int main()
{
   A *a = new A;
   B *b = new B;
 
   connect(a->sig_fun, func);
   connect(a->sig_1, b, &B::slot1);
   connect(a->sig_2, b, &B::slot2);
 
   a->run();
 
   delete a;
   delete b;
   return 0;
}
 

P.S. Valgrind сказал, что утечек нет))

 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
brankovic
Гость
« Ответ #48 : Февраль 26, 2011, 21:47 »

А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #49 : Февраль 26, 2011, 22:17 »

А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Ну вообщето, то что стоит в <> и определяет тип параметра слота..
Однако, можно (но нужно ли?) сделать так, что передавать в сигнал тип, отличный от типа указанного в слоте и уж компилятор сам будет делать преобразование типов. Это делается так:
в класса signal вместо:
Код
C++ (Qt)
template <class T_arg1, class T_arg2 = void>
class signal
{
   ...
 
   void operator() (T_arg1 arg1, T_arg2 arg2) const {
       for (_const_iterator it = _list.begin(); it != _list.end(); it++) {
           if ((*it)->valid())
               (*it)->handle_evant(arg1, arg2);
       }
   }
 

можно заменить на
Код
C++ (Qt)
template <class T_arg1, class T_arg2 = void>
class signal
{
 ...
   template <class U1, class U2>
   void operator() (U1 arg1, U2 arg2) const {
       for (_const_iterator it = _list.begin(); it != _list.end(); it++) {
           if ((*it)->valid())
               (*it)->handle_evant(arg1, arg2);
       }
   }
 
Но я бы не стал так делать..

Короче сейчас с неполным совпадением аргументов не подключить..
А в boostЕ, кстати можно?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #50 : Февраль 26, 2011, 22:46 »

А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Хотя чисто теоретически это возможно, но потребуется некий посредник - объект между сигналом и слотом, в котором и будут храниться все соединения. Тогда типы аргументов можно писать какими угодно..
Вот простой пример, демонстрирующий эту идею:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
class A
{
public:
   ssc::signal<int> sig_a;
 
   void run() const {
      sig_a(2011);
   }
};
 
class B : public ssc::trackable
{
public:
   void slot_b(float x) {
       std::cout << "slot_b, x = " << x << std::endl;
   }
 
};
 
class C : public ssc::trackable
{
public:
   C() {}
   ssc::signal<float> sig_c;
   void slot_c(int x) {
       sig_c(x);
   }
};
 
int main()
{
   A *a = new A;
   B *b = new B;
   C *c = new C;   // перенаправляет сигнал
 
   connect(a->sig_a, c, &C::slot_c);
   connect(c->sig_c, b, &B::slot_b);
 
   a->run();
 
   delete b;
   delete a;
   delete c;
 
   return 0;
}
 
Вобщем идея в том, что соединения теперь нужно чтоб хранил отдельный шаблонный класс, который будет жить сам по седе и следить за всеми общающимися через него объектами..

Как то так)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #51 : Февраль 27, 2011, 01:01 »

А нельзя подключать с неполным совпадением прототипа? т.е. signal <int> к void slot (float)?
Теперь можно))
Решение неожиданно оказалось очень простым без всяких лишних введений посредника c.
Короче, теперь будет работать и так:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
 
class A
{
public:
   ssc::signal<int> sig_a;
 
   ssc::signal<const std::string &> sig_a2;
 
   void run() const {
      sig_a(2011);
      sig_a2("Hello!");
   }
};
 
class B : public ssc::trackable
{
public:
   void slot_b(float x) {
       std::cout << "slot_b, x = " << x << std::endl;
   }
 
   void slot_b2(std::string str) {
       std::cout << str << std::endl;
   }
 
};
 
 
int main()
{
   A *a = new A;
   B *b = new B;
 
   connect(a->sig_a, b, &B::slot_b);
   connect(a->sig_a2, b, &B::slot_b2);
 
   a->run();
 
   delete b;
   delete a;
 
   return 0;
}
 

Исходники приаттачены..
« Последнее редактирование: Февраль 27, 2011, 01:22 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #52 : Февраль 27, 2011, 14:58 »

По этому принципу сделал ещё одно обобщение. Теперь можно соединять сигналы со слотами, у которых число аргументов может быть и меньше, чем число аргументов у сигнала.
Например сейчас можно подсоединить сигнал
Код
C++ (Qt)
ssc::signal<int, float> sig;
 
например с такими слотами:
Код
C++ (Qt)
void slot1();
void slot2(int);
void slot3(int, float); // (float, int); (double, double); (int, int) и т.д.    
 


Note: если имеется несколько перегруженных слотов, то чтоб компилятор понял какой имменно слот подключать к сигналу, нужно явно в шаблонной функции connect указать параметры шаблонов.
прмер:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
#include <cmath>
 
class A
{
public:
   ssc::signal<int> sig_a2;
 
   ssc::signal<const double &, int> sig_a;
 
   void run() const {
 
      sig_a(M_PI, 123);
 
      sig_a2(1);
   }
};
 
class B : public ssc::trackable
{
public:
/* Класс B имеет 2 перегруженных слота */
 
   void slot_b(float x, int y) {
       std::cout << "slot_b, x = " << x << std::endl;
       std::cout << "slot_b, y = " << y << std::endl;
   }
 
   void slot_b() {
       std::cout << "slot_b" << std::endl;
   }
 
   void other_slot() {
       std::cout << "other slot" << std::endl;
   }
 
};
 
int main()
{
   A *a = new A;
   B *b = new B;
 
/* Для того, чтоб не смущать компилятор, нужно в этом случае явно указывать типы шаблонов */
   ssc::connect<B, void, float, int, const double&, int>(a->sig_a, b, &B::slot_b);
   ssc::connect<B, void, const double &, int>(a->sig_a, b, &B::slot_b);
 
/* А здесь всё как обычно, компилятор сам справится  */
   ssc::connect(a->sig_a2, b, &B::other_slot);
 
   a->run();
 
   delete b;
   delete a;
 
   return 0;
}
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #53 : Февраль 28, 2011, 16:23 »

И ещё такой вопрос по поводу потокобезопасности:

Правильно ли то, чтобы гарантировать потокобезопасность соединения необходимо
сделать операцию
Код
C++ (Qt)
spy->set(false);
 
в деструкторе класса trackable атомарной?
Вот код trackable и trigger:
Код
C++ (Qt)
#ifndef TRACKABLE_H
#define TRACKABLE_H
 
#include "smart_ptr.h"
 
namespace ssc {
 
class trigger
{
public:
   trigger() : _flag(true) {}
   void set(bool flag) { _flag = flag; }
   bool get() const { return _flag; }
 
private:
   bool _flag;
};
//-----------------------------------------------------------------------------
 
class trackable
{
public:
   trackable() {
       spy = smart_ptr<trigger>(new trigger);
   }
   virtual ~trackable() {
       spy->set(false);    // Вот это должно быть атомарным?
   }
   smart_ptr<trigger> spy;
};
//-----------------------------------------------------------------------------
 
} /* namespace ssc*/
 
#endif // TRACKABLE_H
 
Или нужно что то большее  Непонимающий
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
brankovic
Гость
« Ответ #54 : Февраль 28, 2011, 18:37 »

И ещё такой вопрос по поводу потокобезопасности:

Правильно ли то, чтобы гарантировать потокобезопасность соединения необходимо
сделать операцию
Код
C++ (Qt)
spy->set(false);
 
в деструкторе класса trackable атомарной?

нет, хотя бы потому, что само по себе присвоение и так атомарно. Чтобы сделать всё потокобезопасным надо в каждый разделяемый элемент системы засунуть мьютекс (в trackable, signal) или же сделать общий для всех операций библиотеки мьютекс. Это работающий вариант, но тяжёлый, плюс безвинно пострадает производительность в однопоточном режиме.

Альтернативно можно попробовать реализовать используя только атомарные операции, но дело не сведётся к простому atomic_inc. Не уверен, что это вообще возможно сделать как-то "просто и изящно".

В качестве иллюстрации: первая версия boost.signals не поддерживала потокобезопасность, и её всё равно приняли -- на тот момент было непонятно, стоит ли жертвовать производительностью ради многопоточности сигналов, которая может ещё никому не понадобится. Высказывалось мнение, что это как написать потокобезопасный вектор, вроде хорошо, но только в разы медленнее. В конце концов выпилили signals2, чтобы никому не было обидно.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #55 : Февраль 28, 2011, 20:44 »

Ясненько)
Значит так просто я не смогу посылать сигналы из одного потока, скажем объекту в другом..
Вернее смогу но нет гарантий, что при выполнении слота, другой поток не прибьёт этот объект.
Или хранить в сигнале не указатели на объекты, а умные указатели (counted_ptr - он же smart_ptr в прошлом) 

Несколько обновил код, в частности,
1) smart_ptr теперь называется counted_ptr
2) метод void set(bool flag) в классе trigger перенёс в private:
Код
C++ (Qt)
class trigger
{
public:
   trigger() : _flag(true) {}
   bool get() const { return _flag; }
 
   friend class trackable;
 
private:
   void set(bool flag) { _flag = flag; }
   bool _flag;
};
 
чтоб никто, кроме trackable не мог изменить состояние объекта.
3) Всё же поскольку случай частный, оставил только передачу одного аргумета (в том числе и void)
не думаю что это вызовет неудобства, зато сразу кода скока поубавилось)

 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #56 : Март 02, 2011, 16:11 »

Зарелизел третью версию libssc  Улыбающийся

Вненсены следующие изменения:
1) mem_fun_connection и fun_connection теперь ничего не знают о signal, что делает их более обособленными (самодостаточными)
2) В signal теперь список соединений содержит не указатели, а counted_ptr на base_connection, что повышает безопасность
3) Функции connect, disconnect перенесены в signal
4) в signal добавлены функции
Код
C++ (Qt)
void disconnect_all() // разрывает все сондинения
 
и
Код
C++ (Qt)
size_t slot_count() const // колличество всех соединений
 
5) Добавлены шаблонные классы messenger4, messenger3, messenger2, содержащие набор данных из 4, 3 и 2 полей соответственно:
Код
C++ (Qt)
template <class T_arg1, class T_arg2>
class messenger2
{
public:
   template <class T1, class T2>
   messenger2(const messenger2<T1, T2> &other)
       : arg1(other.arg1), arg2(other.arg2) {}
   messenger2() {}
   messenger2(const T_arg1 &_arg1, const T_arg2 &_arg2)
       : arg1(_arg1), arg2(_arg2) {}
   T_arg1 arg1;
   T_arg2 arg2;
};
//-----------------------------------------------------------------------------
 
template <class T1, class T2>
inline bool operator== (const messenger2<T1, T2> &p1, const messenger2<T1, T2> &p2)
{
   return ((p1.arg1 == p2.arg1) && (p1.arg2 == p2.arg2));
}
//-----------------------------------------------------------------------------
 
template <class T1, class T2>
inline bool operator!= (const messenger2<T1, T2> &p1, const messenger2<T1, T2> &p2)
{
   return ((p1.arg1 != p2.arg1) || (p1.arg2 != p2.arg2));
}
//-----------------------------------------------------------------------------
 

Пример использования:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
#include "messenger.h"
 
using namespace std;
 
typedef ssc::messenger4<int, int, string, int> dataA;
typedef ssc::messenger4<float, double, string, int> dataB;
 
class A
{
public:
   A() {
       cout << "A()" << endl;
   }
   ~A() {
       cout << "~A()" << endl;
   }
 
   void run() {
       sig_a1(3.14);
       sig_a2(dataA(1, 2, "Hello!", 3));
   }
 
   ssc::signal<float> sig_a1;
   ssc::signal<const dataA &> sig_a2;
};
//-----------------------------------------------------------------------------
 
class B : public ssc::trackable
{
public:
   B() {
       cout << "B()" << endl;
   }
   ~B() {
       cout << "~B()" << endl;
   }
   void slot_b1(int x) {
       cout << "slot_b(int), i = " << x << endl;
   }
 
   void slot_b2(const dataB &x) {
       cout << "slot_b2(const dataB &)" << endl;
       cout << x.arg1 << endl;
       cout << x.arg2 << endl;
       cout << x.arg3 << endl;
       cout << x.arg4 << endl;
   }
   void slot_b2(const dataA &x) {
       cout << "slot_b2(const dataA &)" << endl;
       cout << x.arg1 << endl;
       cout << x.arg2 << endl;
       cout << x.arg3 << endl;
       cout << x.arg4 << endl;
   }
   void slot_b2() {
       cout << "slot_b2()" << endl;
   }
};
//-----------------------------------------------------------------------------
 
int main()
{
   A *a = new A;
   B *b = new B;
 
   a->sig_a1.connect(b, &B::slot_b1); // соединение с неперегруженным слотом
 
/* Слот slot_b2 - перегружен, поэтому необходимо указывать явно параметры шаблонов */
   a->sig_a2.connect<B, void, const dataB &>(b, &B::slot_b2);  /* Note: сигнал отправляет тип dataA, а
слот принимает тип dataB и это сработает!  */

   a->sig_a2.connect<B, void, const dataA &>(b, &B::slot_b2);
   a->sig_a2.connect<B, void>(b, &B::slot_b2);  // И этот слот также сработает
 
   a->run();
 
   delete a;
   delete b;
 
   return 0;
}
 

P.S. Протестировано Valgrind'ом, утечек не обнаружено.
« Последнее редактирование: Март 02, 2011, 16:13 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #57 : Март 05, 2011, 03:47 »

Вышла версия 3.1.1

Добавлен следующий функционал:
1) Поддержка приоритета соединения: Теперь каждое соединение имеет свойство connection_priority:
Код
C++ (Qt)
template <class R_return>
int connection_priority(R_return (*slot)()) const
... // и так далее, для всех типов слотов
 

Обработка слотов идёт в порядке убывания этого значения, т.е. соединение с самым высоким значением обрабатывается первым и т.д.
При отрицательных значениях connection_priority соединение блокируется (не обрабатывается).

По умолчанию connection_priority = 0. Изменить его можно либо явно задав при создании соединения:
Код
C++ (Qt)
a.sig_a.connect(&b, &B::slot_b1, 1); // connection_priority = 1
 

либо с помощью метода:
Код
C++ (Qt)
template <class R_return, class R_arg>
bool set_connection_priority(R_return (*slot)(R_arg), int priority)
...
 
Если изменение приоритета прошло удачно, возвращает true, в противном случае false:
Код
C++ (Qt)
a.sig_a.set_connection_priority(&b, &B::slot_b4, 100); // connection_priority = 100
 


Пример использования:
Код
C++ (Qt)
#include <iostream>
#include "signal_slot.h"
 
using namespace std;
 
class A
{
public:
   ssc::signal<int> sig_a;
 
   void run() const {
       sig_a(123);
   }
};
 
class B : public ssc::trackable
{
public:
   void slot_b1(int x) {
       cout << "slot_b1, x = " << x << endl;
   }
 
   void slot_b2(int x) {
       cout << "slot_b2, x = " << x << endl;
   }
 
   void slot_b3(int x) {
       cout << "slot_b3, x = " << x << endl;
   }
 
   void slot_b4() {
       cout << "slot_b4" << endl;
   }
 
   void slot_b5() {
       cout << "slot_b5" << endl;
   }
};
 
int main()
{
   A a;
   B b;
   /* по умолчанию connection_priority = 0*/
   a.sig_a.connect(&b, &B::slot_b1, 1);
   a.sig_a.connect(&b, &B::slot_b2, 2);
   a.sig_a.connect(&b, &B::slot_b3, 3);
   a.sig_a.connect(&b, &B::slot_b4, 4);
   a.sig_a.connect(&b, &B::slot_b5, 5);
 
   a.sig_a.set_connection_priority(&b, &B::slot_b4, 100);
 
   cout << "slot_b1, priority = " << a.sig_a.connection_priority(&b, &B::slot_b1) << endl;
   cout << "slot_b2, priority = " << a.sig_a.connection_priority(&b, &B::slot_b2) << endl;
   cout << "slot_b3, priority = " << a.sig_a.connection_priority(&b, &B::slot_b3) << endl;
   cout << "slot_b4, priority = " << a.sig_a.connection_priority(&b, &B::slot_b4) << endl;
   cout << "slot_b5, priority = " << a.sig_a.connection_priority(&b, &B::slot_b5) << endl;
 
   cout << endl;
 
   a.run();
 
   return 0;
}
 

« Последнее редактирование: Март 09, 2011, 17:15 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #58 : Март 10, 2011, 14:31 »

Вышла версия libssc-4

Качественно изменена архитектура, что позволяе достаточно просто расширять функционал до любого числа передоваемых параметров в сигнале.

Пока ограничился случаем с числом параметров 2.
Поддерживается не неполное совпадение прототипа, т.е можно соединять:
signal<int, int> например со слотом func(float, float) и т. д.
Число параметров сигнала должно совпадать с числом параметров слота.

пример:
Код
C++ (Qt)
#include <iostream>
#include "signal_slot.h"
#include <cmath>
 
using namespace std;
 
class A
{
public:
   ssc::signal<void> sig_a0;
   ssc::signal<int> sig_a1;
   ssc::signal<int, float> sig_a2;
 
   void run() const {
       sig_a0();
       sig_a1(123);
       sig_a2(4, 2.5);
   }
};
 
class B : public ssc::trackable
{
public:
 
   void slot_b0() {
       cout << "slot_b0" << endl;
   }
 
   void slot_b1(int x) {
       cout << "slot_b1, x = " << x << endl;
   }
 
   double slot_b2(double x, float y) {
       double res = pow(x, y);
       cout << "slot_b2, x^y = " << res <<  endl;
       return res;
   }
};
 
 
int main()
{
   A a;
   B b;
 
   a.sig_a0.connect(&b, &B::slot_b0);
   a.sig_a1.connect(&b, &B::slot_b1);
   a.sig_a2.connect(&b, &B::slot_b2);
 
   a.run();
 
   return 0;
}
 

  
« Последнее редактирование: Июль 16, 2011, 20:20 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #59 : Июль 16, 2011, 21:04 »

В ходе внедрения libssc в ядро одной программки выявилась одна маленькая неприятность Грустный , которая впрочем сейчас устранена. Хотя не знаю насколько это правильно..

1) Дело в том, что если необходимо скопировать один объект (который имеет свои сигналы) другому объекту, то в результате второй объект приобретает и все списки соединений, что имел первый объект. Что как то противоестественно, имхо..
В boost::signals и в libsic++ это решено просто запретом копирования объектов (NonCopybal) А иногда этого хочется)

2) Во-вторых в предыдущем варианте libssc следующий код работал неправильно
Код
C++ (Qt)
class A
{
public:
   ssc::signal<void> sig_a0;
 
   void run() const {
       sig_a0();
   }
};
 
class B : public ssc::trackable
{
public:
   void slot() const { cout << "slot B" << endl; }
};
 
int main()
{
  A a;
  B b;
  {
       B b_other;
       a.sig_a0.connect(&b_other, &B::slot);
       b_other = b;
  }
   a.run();
  return 0;
}
 
   
По идеи метод a.run() не должен вызывать слот, поскольку объект b_other - уже разрушен, однако, присваивание
b_other = b
меняет ситуацию, что не есть гут)

Проблема сейчас решена переопределением оператора присваивания и копирующего конструктора в классах trackable и signal
Код
C++ (Qt)
class trackable
{
public:
   trackable(const trackable &) {
       spy = counted_ptr<trigger>(new trigger);
   }
   trackable &operator=(const trackable &) { return *this; } // Оператор присваивания ничего не делает
   trackable() {
       spy = counted_ptr<trigger>(new trigger);
   }
   virtual ~trackable() {
       spy->set(false);
   }
   counted_ptr<trigger> spy;
};
 
И аналогично у signal
Код
C++ (Qt)
   signal2(const signal2<S_arg1, S_arg2> &) {} // Пуст
   signal2<S_arg1, S_arg2> &operator=(const signal2<S_arg1, S_arg2> &) { return *this; } // Ничего не делает
 
Короче, присваивание и конструктор копирования ничего не делают, но совсем без них поведение было бы неправильным.

Теперь можно копировать, присваивать, но для каждого объекта должны индивидуально создаваться с-с соединения, что имхо, вполне логично.

   
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: 1 2 3 [4] 5 6 ... 8   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.653 секунд. Запросов: 23.