Больше, лучше, быстрее
Больше, лучше, быстрее
Реализация делегатов, которую мы рассмотрели выше, вполне работоспособна. Тем не менее, некоторые её особенности вызывают озабоченность. Во-первых, интенсивное использование шаблонов может привести к чрезмерному разбуханию кода. Во-вторых, объекты делегатов распределяются динамически (при помощи оператора 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) {
if ((*it)-›Compare(pDelegate)) {
delete (*it);
m_DelegateList.erase(it);
break;
}
}
}
void RemoveAll() {
DelegateList::iterator it;
for (it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it) delete (*it);
m_DelegateList.clear();
}
protected:
DelegateList m_DelegateList;
};
Теперь реализация класса CDelegateX существенно упрощается. В нём останутся только операторы (для которых используется inline-подстановка) и метод Invoke. Только этот метод и будет сгенерирован отдельно для каждой специализации - хороший результат по сравнению с тем, что было раньше. Новая реализация класса CDelegateX будет выглядеть так:
template‹class TRet TEMPLATE_PARAMS›
class C_DELEGATE: public CDelegateImpl {
public:
typedef I_DELEGATE‹TRet TEMPLATE_ARGS› IDelegate;
C_DELEGATE(IDelegate* pDelegate = NULL): CDelegateImpl(pDelegate) {}
C_DELEGATE‹TRet TEMPLATE_ARGS›& operator=(IDelegate* pDelegate) {
RemoveAll();
Add(pDelegate);
return *this;
}
C_DELEGATE‹TRet TEMPLATE_ARGS›& operator+=(IDelegate* pDelegate) {
Add(pDelegate);
return *this;
}
C_DELEGATE‹TRet TEMPLATE_ARGS›& operator-=(IDelegate* pDelegate) {
Remove(pDelegate);
return *this;
}
TRet operator()(PARAMS) {
return Invoke(ARGS);
}
private:
TRet Invoke(PARAMS) {
DelegateList::const_iterator it;
for (it = m_DelegateList.begin(); it!= --m_DelegateList.end(); ++it) static_cast‹IDelegate*› (*it)-›Invoke(ARGS);
return static_cast‹IDelegate*› (m_DelegateList.back())-›Invoke(ARGS);
}
};
Обратите внимание на появившиеся приведения типов. В данном случае они никак не сказываются на типобезопасности делегатов, так как в списке m_DelegateList могут храниться только указатели на объекты классов CStaticDelegateX и CMethodDelegateX, а эти указатели заведомо приводятся к указателю на IDelegate.
В заключение несколько слов о проблеме производительности. Как уже говорилось, она может возникать из-за распределения объектов делегатов в куче. К сожалению, реализовать делегаты как стековые объекты не представляется возможным, так как для них существенным свойством является полиморфное поведение. Но и тут ситуацию можно существенно улучшить. Поскольку все делегаты централизованно создаются внутри функции NewDelegate, для них вполне возможно написать специализированный аллокатор, который будет распределять память для делегатов быстро и эффективно. Написание такого аллокатора оставляется читателю в качестве упражнения.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Что быстрее: gzip или канал?
Что быстрее: gzip или канал? Модель хорошо аппроксимирует полученные данные, поэтому примем ее за основу для следующих вычислений. Нам нужно, на самом деле, установить, насколько процессорные издержки на сжатие превосходят (или, наоборот, меньше) издержек на передачу
Что быстрее?
Что быстрее? Да, очевидно, что размер DOM-дерева влияет на скорость загрузки страницы. Одной из целей данного исследования было показать, как именно влияет (в конкретных числах). Средний размер страницы — 700-1000 элементов. Они загрузятся в дерево сравнительно быстро (3-7 мс, без
DOM DocumentFragment: быстрее быстрого
DOM DocumentFragment: быстрее быстрого DocumentFragment является облегченным контейнером для DOM-узлов. Он описан в спецификации DOM1 и поддерживается во всех современных браузерах (был добавлен в Internet Explorer в 6-й версии).В спецификации говорится, что различные операции — например, добавление
А если еще быстрее?
А если еще быстрее? Давайте подумаем еще немного. Зачем нам каждый раз создавать фрагмент документа, если мы для этой цели можем использовать обычный его узел (фактически создавать кэш нашего узла, который мы собираемся везде менять)? Так можно прийти к следующему
Быстрее и лучше
Быстрее и лучше Чтобы растения росли максимально быстро, пашня должна быть увлажнена, а урожай – хорошо освещен в ночное время. Для увлажнения пашни поместите источник воды в пределах четырех блоков. Если у вас пока нет ведра для воды, сажайте растения около пруда.
7.6. Проще, удобнее, быстрее
7.6. Проще, удобнее, быстрее Процесс конфигурирования должен быть максимально удобным. Если все настройки будут нагромождены в одном файле /etc/httpd/conf/httpd.conf, то разобраться в них станет очень сложно. А чем больше параметров, тем выше вероятность, что вы что-либо прозеваете.
15.8.5. Лучше, чем IDE
15.8.5. Лучше, чем IDE Ранее в данной главе утверждалось, что Emacs способен предоставить программисту возможности, аналогичные возможностям какой-либо традиционной интегрированной среды разработки и даже превосходящие их. К настоящему моменту у читателя должно быть
FERRMA: Быстрее, быстрее, сейчас же… Немедленно!
FERRMA: Быстрее, быстрее, сейчас же… Немедленно! Автор: Алексей СтародымовТак уж сложилось, что производители мобильных телефонов не считают нужным сообщать, какая именно аппаратная платформа используется в той или иной модели, семействе или даже поколении устройств. Оно и
Windows + Android: больше — значит лучше? Евгений Золотов
Windows + Android: больше — значит лучше? Евгений Золотов Опубликовано 09 января 2014 Перспектива превращения Android в операционную систему для «полноразмерных вычислительных машин» нарисовалась ещё полгода назад. К тому моменту на рынке уже имелось или
ОГОРОД КОЗЛОВСКОГО: Heavy metal, или Лучше меньше, да лучше
ОГОРОД КОЗЛОВСКОГО: Heavy metal, или Лучше меньше, да лучше Автор: Козловский ЕвгенийНа Новый год, в числе прочего, получился новенький фотоаппарат от Casio: EX S770. Последняя на тот момент и безусловно лучшая модель! Совершенная в своем роде. Таким образом, смутная мечта всегда
Глава 8 Как заставить компьютер работать быстрее
Глава 8 Как заставить компьютер работать быстрее Способы повышения производительности Говорят, что торопить компьютер – это все равно что торопить женщину. Но на практике оказывается, что заставить компьютер работать быстрее все же можно.Вот некоторые способы