Russian Qt Forum

Программирование => С/C++ => Тема начата: xokc от Июнь 27, 2012, 12:40



Название: Замена switch
Отправлено: xokc от Июнь 27, 2012, 12:40
Есть почти классическая задача - TCP получает сервер вынимает из QTcpSocket заголовок сообщения, в нём получает некий id сообщения и должен вызвать соответсвующий обработчик. Сейчас это реализовано через длинный switch вида
Код
C++ (Qt)
 
   switch (header->id) {
   case ind::Start:
       emit start(header->data);
       break;
   }
   case ind::Stop:
       emit stop(header->data);
       break;
   }
   case ind::Pause:
       emit pause(header->data);
       break;
   }
   default:
       qWarning() << tr("Unknown command: id = %1, size = %2").arg(header->id).arg(header->data->size));
   }
 

По понятным архитектурным причинам (очень уж switch длинный, плохо расширяемый и т.п.) хотелось бы уйти от этого switch в пользу, например, хеша с ключами в виде enum и значениями в виде сигналов. Т.е. case будет заменен на нечто подобное:
Код
C++ (Qt)
 
if (m_hash.contains(header->id))
   QMetaObject::invokeMethod(this, m_hash.value(header->id), QT_ARG(QByteArray, header->data));
 
Какие недостатки у такого решения, кроме неизбежных накладных расходов на косвенный вызов методов? Какие еще есть варианты ухода от длинного switch?


Название: Re: Замена switch
Отправлено: alexis031182 от Июнь 27, 2012, 12:53
...
Какие недостатки у такого решения, кроме неизбежных накладных расходов на косвенный вызов методов? Какие еще есть варианты ухода от длинного switch?
А разве в switch у Вас не тоже самое делается, что и в случае с invokeMethod? Такой же "косвенный" вызов только через emit. Рекомендую на сервере отказаться от использования сигнал/слотов, если Вам нужна скорость. Впрочем, если Вы используете QTcpServer, то моя рекомендация не имеет ценности, конечно :)

А вообще, задействуйте фабрику методов. Тот же QMetaType существенно универсализирует код.


Название: Re: Замена switch
Отправлено: kuzulis от Июнь 27, 2012, 13:03
Можно хранить константный массив указателей на обработчики методов типа start, pause ...,
где итераторами массива будут значения id, (с условием, что они с нуля начинаются) тогда переписать можно так:

Код
C++ (Qt)
typedef MyHandler ... *handler(...);
 
static const MyHandler table[3] = { start, stop, pause };
 
...
emit table[header->id](header->data);
...
 
 

Как то так.. :)


Название: Re: Замена switch
Отправлено: Igors от Июнь 27, 2012, 13:16
Какие недостатки у такого решения, кроме ..
Ощутимым может оказаться затруднение отладки, нужно как-то прорваться в invoke чтобы понять что вызывается


Название: Re: Замена switch
Отправлено: xokc от Июнь 27, 2012, 13:17
Рекомендую на сервере отказаться от использования сигнал/слотов, если Вам нужна скорость.
Отказаться в пользу чего?

Впрочем, если Вы используете QTcpServer, то моя рекомендация не имеет ценности, конечно :)
Дело в том, что сервер у меня не очень классический. Максимальное одновременное количество клиентов - не более 256, обычно - до 8. Но каждый из клиентов для сервера достаточно "прожорлив" как по памяти, так и по вычислительной нагрузке, при этом поток управляющих воздействий от клиента на сервер невелик (по сути - трансляция пользовательского интерфейса), а вот от сервера к клиенту трафик достаточно велик (по структуре похож на видео сигнал). До сих пор возможностей QTcpServer с большим запасом хватало, но сейчас есть разрабатывается новая версия и есть возможность уйти к чему-нибудь другому. Вопрос - к чему и ради чего?


Название: Re: Замена switch
Отправлено: xokc от Июнь 27, 2012, 13:19
Ощутимым может оказаться затруднение отладки, нужно как-то прорваться в invoke чтобы понять что вызывается
С этим готов мириться


Название: Re: Замена switch
Отправлено: alexis031182 от Июнь 27, 2012, 13:28
Отказаться в пользу чего?
Сигнал/слоты - очень удобное решение, но медленнее, нежели прямой вызов функций. Это известно.

Дело в том, что сервер у меня не очень классический. Максимальное одновременное количество клиентов - не более 256, обычно - до 8. Но каждый из клиентов для сервера достаточно "прожорлив" как по памяти, так и по вычислительной нагрузке, при этом поток управляющих воздействий от клиента на сервер невелик (по сути - трансляция пользовательского интерфейса), а вот от сервера к клиенту трафик достаточно велик (по структуре похож на видео сигнал). До сих пор возможностей QTcpServer с большим запасом хватало, но сейчас есть разрабатывается новая версия и есть возможность уйти к чему-нибудь другому. Вопрос - к чему и ради чего?
Если возможностей QTcpServer достаточно, то
... то моя рекомендация не имеет ценности, конечно :)
Если у Вас малое количество соединений, малый входящий трафик и исходящий, хотя и тяжёлый, но не особо критичен ко скорости отдачи, то по идее QTcpServer - нормальное решение.


Название: Re: Замена switch
Отправлено: DmitryM от Июнь 28, 2012, 10:13
map с lambda функциями.