
В программе, изобилующей мелкими объектами, иногда необходимо выяснить, сколько именно объектов создано, сотня или же миллион. А если объекты создаются и уничтожаются постоянно в течение жизненного цикла программы, то зачастую интересует вопрос, сколько раз были созданы объекты того или иного типа?
Ключевые элементы такого счетчика объектов вырисовываются сразу: некие глобальные переменные и привязка к типам объектов.
Сразу хочется сказать о подводных камнях, которые обнаруживаются в процессе организации счетчика. Дело в том, что классы как правило имеют наследование, поэтому простое инкрементирование счетчика в каждом конструкторе никуда не годится — при вызове конструктора будут инкрементированы и счетчики всех базовых классов.
В приведенной далее реализации счетчика объектов используется соглашение, что базовый класс отмечается разработчиком. Для различения счетчиков разных объектов используется шаблонный класс, который специфицируется типом. (Возможно, альтернативным более компактным решением было бы специфицирование шаблона строкой, получаемой из typeid при подстановке this.) Счетчик, установленный в каком либо классе, обязательно должен быть установлен и во всех его производных классах, если только Вы не хотите, чтобы объекты производных классов подсчитывались в одной куче с объектами базовых классов.
Читать дальше... //------------------------------------------------------------ #include <memory> class InstanceCounterBase { public: virtual void SubOne()=0; static std::auto_ptr<InstanceCounterBase> m_PrevCounter; }; std::auto_ptr<InstanceCounterBase> InstanceCounterBase::m_PrevCounter; //------------------------------------------------------------ template <class T> class InstanceCounter: InstanceCounterBase { private: InstanceCounter() { ++m_Counter; } void SubOne() { --m_Counter; } public: static int Value() { return m_Counter; } static void Install(bool Base=false) { if (Base) { m_PrevCounter.release(); } if (m_PrevCounter.get()) { m_PrevCounter->SubOne(); } m_PrevCounter.reset(new InstanceCounter<T>()); } private: static int m_Counter; }; template <class T> int InstanceCounter<T>::m_Counter=0; //------------------------------------------------------------
|
Счетчик устанавливается на объект класса в конструкторе вызовом метода Install. При установке счетчика на базовый класс необходимо вызвать метод Install с параметром true, что является для счетчика признаком базового класса.
//------------------------------------------------------------ class Base { public: Base() { InstanceCounter<Base>::Install(true); // пометка базового класса } }; class Derived: virtual public Base { public: Derived(): Base() { InstanceCounter<Derived>::Install(); } }; class Derived2: virtual public Base { public: Derived2(): Base() { InstanceCounter<Derived2>::Install(); } }; class Derived2_2: public Derived2 { public: Derived2_2(): Derived2() { InstanceCounter<Derived2_2>::Install(); } }; class SuperDerived: public Derived, public Derived2 { public: SuperDerived(): Derived(), Derived2() { InstanceCounter<SuperDerived>::Install(); } }; class Another { public: Another() { InstanceCounter<Another>::Install(true); // другой базовый класс } }; //------------------------------------------------------------ #include <iostream> int main() { Derived D1, D2, D3; Base B1, B2; Another A1, A2; Derived2_2 D2_21; SuperDerived SD1; std::cout << "Base #" << InstanceCounter<Base>::Value() << std::endl; std::cout << "Derived #" << InstanceCounter<Derived>::Value() << std::endl; std::cout << "Derived2 #" << InstanceCounter<Derived2>::Value() << std::endl; std::cout << "Derived2_2 #" << InstanceCounter<Derived2_2>::Value() << std::endl; std::cout << "SuperDerived #" << InstanceCounter<SuperDerived>::Value() << std::endl; std::cout << "Another #" << InstanceCounter<Another>::Value() << std::endl; return 0; } //------------------------------------------------------------
|
В примере создана некоторая иерархия классов, создано по несколько объектов каждого класса и результат подсчета количества объектов выведен на экран.
//------------------------------------------------------------ Base #2 Derived #3 Derived2 #0 Derived2_2 #1 SuperDerived #1 Another #2 //------------------------------------------------------------
|
Все правильно, и при обычном наследовании счетчик работает корректно. Счетчик корректно работает и при виртуальном наследовании. Для множественного наследования такой счетчик работает при условии, что иерархия классов имеет один базовый класс. В общем случае, для множественного наследования нужно искать другое решение, либо вовсе не устанавливать такой счетчик в базовые классы.
Thread-safe оптимизированный вариант счетчика, предложенный моим коллегой, сопряжен с использованием множественного наследования, и содержит три класса. Однако прост для понимания, и категорически рекомендован к использованию.
Читать дальше...
А теперь умри силою моего гения!!! Я тебя щас повергну в смертельный шок и растопчу в пыль и прах твой жалкий труп следующим своим заклинанием:
Тут уж соглаСИСЬКА - реализация гениальна своей простотой!!!
Казалось бы, подкопаться не к чему, но я подкопаюсь.
Подкопаться тут можно к трем вещам. Во-первых, нафиг столько раз создавать временный объект CounterBaseObj? На него любой уважающий себя (кроме борландовского) компилятор будет орать, мол, unreferenced local variable. Во-вторых, зачем делать friend'ом класс Counter, если CounterBase находится в секции private, и никто и никогда не доберется до поля m_Count извне — можно его сделать в public, а friend тут совершенно неуместен. И в-третьих, даже младшая группа ясельного сада знает, что префиксные операции быстрее постфиксных, потому что не создают временных объектов
Так что оставляю последнее слово за собой.
Пользуйтесь
Вот теперь в таком виде это почти божественно!!!
MZ шучу конечно, но вы парни действительно знаете толк в программинге.
В общем круто - так держать.
Да и по большей части все трюки описаны в специальной литературке.
Examine these most effective methods for Web site promotion:
https://telegra.ph/Prodvizhenie-sajta-ssylkami-Kurs-seo-optimizacii-469839-12-05
https://telegra.ph/Prodvizhenie-sajta-ssylkami-Ssylki-dlya-raskrutki-sajta-562051-12-05
https://telegra.ph/Prodvizhenie-sajta-ssylkami-Prodvizhenie-sajtov-vechnymi-ssylkami-671391-12-05
https://telegra.ph/Prodvizhenie-sajta-ssylkami-Link-building-495731-12-05
https://telegra.ph/Prodvizhenie-sajta-ssylkami-Poluchenie-seo-ssylok-838556-12-05
If intrigued, generate to PM and guide early obtain