В программе, изобилующей мелкими объектами, иногда необходимо выяснить, сколько именно объектов создано, сотня или же миллион. А если объекты создаются и уничтожаются постоянно в течение жизненного цикла программы, то зачастую интересует вопрос, сколько раз были созданы объекты того или иного типа?
Ключевые элементы такого счетчика объектов вырисовываются сразу: некие глобальные переменные и привязка к типам объектов.
Сразу хочется сказать о подводных камнях, которые обнаруживаются в процессе организации счетчика. Дело в том, что классы как правило имеют наследование, поэтому простое инкрементирование счетчика в каждом конструкторе никуда не годится — при вызове конструктора будут инкрементированы и счетчики всех базовых классов.
В приведенной далее реализации счетчика объектов используется соглашение, что базовый класс отмечается разработчиком. Для различения счетчиков разных объектов используется шаблонный класс, который специфицируется типом. (Возможно, альтернативным более компактным решением было бы специфицирование шаблона строкой, получаемой из typeid при подстановке this.) Счетчик, установленный в каком либо классе, обязательно должен быть установлен и во всех его производных классах, если только Вы не хотите, чтобы объекты производных классов подсчитывались в одной куче с объектами базовых классов.
Читать дальше...

Thread-safe оптимизированный вариант счетчика, предложенный моим коллегой, сопряжен с использованием множественного наследования, и содержит три класса. Однако прост для понимания, и категорически рекомендован к использованию.
Читать дальше...

@темы: Трюки с наследованием, Счётчики объектов

Комментарии
21.03.2008 в 18:57


А теперь умри силою моего гения!!! Я тебя щас повергну в смертельный шок и растопчу в пыль и прах твой жалкий труп следующим своим заклинанием:





/**
* @class Counter
* Базовый класс иерархии классов, объекты которых будут подсчитываться.
* Класс Counter содержит указатель InstanceCounterBase * m_PrevCounter
* - указатель на предыдущий счётчик, таким образом он будет присутствовать во всех
* пораждённых классах в иерархии. В каждом конструкторе необходимо вставить
* строчку "Install<тип класса>();". Во время создания объекта класса, в порождённых
* классах будет декрементироваться счётчик базового или предыдущего класса,
* указателю m_PrevCounter присвается адрес собственного счётчика, после чего инкрементироваться
* счётчик собственного класса. Следовательно счётчик, который был увеличен базовым классом,
* будет уменьшен порождённым и инкрементированным останется только последний класс в иерархии.
* При разрушении объекта, когда дойдёт дело до деструктора класса Counter, то указатель
* m_PrevCounter будет содержать указатель на счётчик последнего класса иерархии
* и декрементирует его.
*/

class Counter {
template <class T> class CounterBase {
friend class Counter;
static int m_Count;
};
protected:
int * m_PrevCounter;
public:
Counter(void) {
CounterBase<Counter> CounterBaseObj;
m_PrevCounter = &(CounterBaseObj.m_Count);
(*m_PrevCounter)++;
}
~Counter(void) {
(*m_PrevCounter)--;
}
template <class T> void Install(void) {
CounterBase<T> CounterBaseObj;
(*m_PrevCounter)--;
m_PrevCounter = &(CounterBaseObj.m_Count);
(*m_PrevCounter)++;
}
template <class T> static int Count(void) {
CounterBase<T> CounterBaseObj;
return CounterBaseObj.m_Count;
}
};
template <class T> int Counter::CounterBase<T>::m_Count = 0;

/**
* Данный макрос предназначен для более компактной и понятной записи.
* @return - возвращает количество объектов класса type.
*/

#define COUNTOF(type) Counter::Count<type>()




Тут уж соглаСИСЬКА - реализация гениальна своей простотой!!!




21.03.2008 в 21:15

Чортовы гении... У меня защита пятого уровня против вашего заклинания.
Казалось бы, подкопаться не к чему, но я подкопаюсь.
Подкопаться тут можно к трем вещам. Во-первых, нафиг столько раз создавать временный объект CounterBaseObj? На него любой уважающий себя (кроме борландовского) компилятор будет орать, мол, unreferenced local variable. Во-вторых, зачем делать friend'ом класс Counter, если CounterBase находится в секции private, и никто и никогда не доберется до поля m_Count извне — можно его сделать в public, а friend тут совершенно неуместен. И в-третьих, даже младшая группа ясельного сада знает, что префиксные операции быстрее постфиксных, потому что не создают временных объектов:)
Так что оставляю последнее слово за собой.
Пользуйтесь:)
class Counter {
template <class T> class CounterBase {
public:
static int m_Count;
};
int * m_PrevCounter;
public:
Counter(void): m_PrevCounter(&(++CounterBase<Counter>::m_Count)) {}
~Counter(void) {
--(*m_PrevCounter);
}
template <class T> void Install(void) {
--(*m_PrevCounter);
m_PrevCounter = &(++CounterBase<T>::m_Count);
}
template <class T> static int Count(void) {
return CounterBase<T>::m_Count;
}
};
template <class T> int Counter::CounterBase<T>::m_Count = 0;

21.03.2008 в 22:16

Блин, даже спорить не буду, согласен на все 100%. Поторопился, идею реализовал, но до совершенства не довёл. Ну надо же было хоть немного и тебе дать возможность приложить руки и голову =))).
Вот теперь в таком виде это почти божественно!!!
22.03.2008 в 15:35

Вот теперь в таком виде это почти божественно!!!

:beer:
30.05.2008 в 01:26

ну вы парни даете... Сознаю перед вами свою убогость и впредь обязуюсь исполнять вашу волю по любому случаю... хехе.ехе
MZ шучу конечно, но вы парни действительно знаете толк в программинге.
В общем круто - так держать.
26.08.2008 в 23:42

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

Расширенная форма

Редактировать

Подписаться на новые комментарии
Получать уведомления о новых комментариях на E-mail