Делегаты на C++ | страница 12



Больше, лучше, быстрее

Реализация делегатов, которую мы рассмотрели выше, вполне работоспособна. Тем не менее, некоторые её особенности вызывают озабоченность. Во-первых, интенсивное использование шаблонов может привести к чрезмерному разбуханию кода. Во-вторых, объекты делегатов распределяются динамически (при помощи оператора new). Поскольку на создание объектов в куче тратится гораздо больше времени, чем на создание стековых объектов, это может привести к проблемам производительности. В этом разделе мы рассмотрим некоторые пути преодоления этих проблем.

С точки зрения разбухания кода наиболее неблагополучно выглядит класс CDelegateX. Его специализация генерируется для каждой сигнатуры, для которой будет использоваться делегат. Но методы Add, Remove и RemoveAll никак не используют информацию о сигнатуре. То есть для этих методов каждый раз будет генерироваться один и тот же код. Чтобы изменить ситуацию, можно вынести реализацию этих методов в отдельный нешаблонный класс CDelegateImpl. Тогда все специализации шаблона IDelegateX унаследуют эту реализацию, и она останется в программе в единственном экземпляре.

Чтобы реализовать эту идею, для начала разобьём интерфейс IDelegateX на два интерфейса. Базовый, IComparableDelegate, будет "отвечать" за сравнение делегатов. Производный, уже знакомый нам IDelegateX, будет определять дополнительный метод Invoke.

>class IComparableDelegate {

>public:

> virtual ~IComparableDelegate() {}

> virtual bool Compare(IComparableDelegate* pDelegate) = 0;

>};


>template‹class TRet TEMPLATE_PARAMS›

>class I_DELEGATE: public IComparableDelegate {

>public:

> virtual TRet Invoke(PARAMS) = 0;

>};


Обратите внимание, что в интерфейсе IComparableDelegate шаблоны не используются. Теперь в терминах этого интерфейса можно реализовать базовый класс CDelegateImpl, который будет отвечать за поддержку списка делегатов. Соответственно, в нём будут реализованы методы Add, Remove и Invoke.

>class CDelegateImpl {

>public:

> typedef std::list‹IComparableDelegate*› DelegateList;

> CDelegateImpl(IComparableDelegate* pDelegate = NULL) { Add(pDelegate); }

> ~CDelegateImpl() { RemoveAll(); }

> bool IsNull() { return (m_DelegateList.empty()); }

>protected:

> void Add(IComparableDelegate* pDelegate) {

>  if (pDelegate != NULL) m_DelegateList.push_back(pDelegate);

> }

> void Remove(IComparableDelegate* pDelegate) {

>  DelegateList::iterator it;

>  for (it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it) {