Эволюция базового интерфейса
На самом нижнем уровне IBProvider и всех моих остальных, более менее крупных, проектов на С++ лежит единый базовый класс с парой методов — add_ref и release, управляющих счетчиком ссылок на объект.
Судя по истории репозитария (CVS), который был запущен 21 декабря 2000 года, этот класс появился раньше. Наверное, где-то в районе конца 99-го или начала 2000-го кода.
Забавно посмотреть на этапы эволюции этой конструкции, лежащей в основе всей архитектуры.
2000-12-21. Первоначальный вариант.
//////////////////////////////////////////////////////////////////////////////// // облегченные варианты COM объекта class t_smart_object { long m_cntRef; public: t_smart_object():m_cntRef(0){;} protected: virtual ~t_smart_object(){assert(m_cntRef==0);} public: virtual long add_ref(){return ::InterlockedIncrement(&m_cntRef);} virtual long release(){return ::InterlockedDecrement(&m_cntRef);} long get_cntRef(){return m_cntRef;} }; /////////////////////////////////////////////////////////////////////////////// // упрошенный вариант COM-объекта class t_smart_memory_object:public t_smart_object { public: long release() { long cntRef=t_smart_object::release(); if(cntRef==0) delete this; return cntRef; } };
2001-06-24. Осознание, что нужно определять и прятать конструктор и оператор копирования.
//////////////////////////////////////////////////////////////////////////////// // облегченные варианты COM объекта class t_smart_object { private: t_smart_object(const t_smart_object&); t_smart_object& operator = (const t_smart_object&); private: long m_cntRef; protected: //только для наследования t_smart_object():m_cntRef(0){;} virtual ~t_smart_object(){assert(m_cntRef==0);} public: virtual long add_ref(){return ::InterlockedIncrement(&m_cntRef);} virtual long release(){return ::InterlockedDecrement(&m_cntRef);} long get_cntRef() const {return m_cntRef;} }; /////////////////////////////////////////////////////////////////////////////// // упрошенный вариант COM-объекта class t_smart_memory_object:public t_smart_object { private: t_smart_memory_object(const t_smart_memory_object&); t_smart_memory_object& operator = (const t_smart_memory_object&); protected: //только для наследования t_smart_memory_object(){;} public: long release() { long cntRef=t_smart_object::release(); if(cntRef==0) delete this; return cntRef; } };
2002-05-08. Добавили отладочный контроль времени жизни. Наверное, после очередного удара граблями по лбу.
/////////////////////////////////////////////////////////////////////////////// // упрошенный вариант COM-объекта class t_smart_memory_object:public t_smart_object { private: t_smart_memory_object(const t_smart_memory_object&); t_smart_memory_object& operator = (const t_smart_memory_object&); DEBUG_CODE(bool m_is_destroyed;) protected: //только для наследования t_smart_memory_object() { DEBUG_CODE(m_is_destroyed=false); } public: long release() { assert(!m_is_destroyed); long cntRef=t_smart_object::release(); if(cntRef==0) { DEBUG_CODE(m_is_destroyed=true;) delete this; } return cntRef; } };//class t_smart_memory_object
2002-09-19. Нормализация определения класса. По моему, это через три дня после запуска проекта для «недвижимости» для которого IBProvider изначально и создавался.
/////////////////////////////////////////////////////////////////////////////// // упрошенный вариант COM-объекта class t_smart_memory_object:public t_smart_object { private: t_smart_memory_object(const t_smart_memory_object&); t_smart_memory_object& operator = (const t_smart_memory_object&); DEBUG_CODE(bool m_is_destroyed;) protected: t_smart_memory_object() { DEBUG_CODE(m_is_destroyed=false); } public: long release(); };//class t_smart_memory_object
2004-04-22. Переделываем на шаблоны (очередная стадия развития программиста на плюсах) и начинаем юзать внешний сервис для инкремента/декремента счетчика ссылок (thread_traits). Кстати, явно указываем virtual у t_basic_smem_obj::release — это борьба с багами компилятора BCB.
//////////////////////////////////////////////////////////////////////////////// //class t_basic_sobj template<class thread_traits> class t_basic_sobj { private: typedef t_basic_sobj<thread_traits> self_type; t_smart_object(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------ typedef thread_traits thread_traits_type; typedef typename thread_traits_type::int_type cnt_ref_type; protected: //inherited only --------------------------------------------- t_basic_sobj() :m_cntRef(0) {;} virtual ~t_basic_sobj(); public: virtual cnt_ref_type add_ref(); virtual cnt_ref_type release(); public: cnt_ref_type get_cntRef() const {return m_cntRef;} private: cnt_ref_type m_cntRef; };//class t_basic_sobj //backward compatibility typedef t_basic_sobj<t_def_thread_traits> t_smart_object; /////////////////////////////////////////////////////////////////////////////// //class t_basic_smem_obj template<class thread_traits,class Allocator> class t_basic_smem_obj:public t_basic_sobj<thread_traits> { private: typedef t_basic_smem_obj<thread_traits,Allocator> self_type; typedef t_basic_sobj<thread_traits> inherited; t_smart_memory_object(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------- typedef typename inherited::cnt_ref_type cnt_ref_type; protected: t_basic_smem_obj() {DEBUG_CODE(m_is_destroyed=false);} virtual ~t_basic_smem_obj(); public: //t_basic_sobj interface ----------------------------------------- virtual cnt_ref_type release(); public: static void* operator new (size_t sz) {return Allocator().allocate(sz);} static void operator delete (void* pv) {Allocator().deallocate(pv,0);} private: DEBUG_CODE(bool m_is_destroyed;) };//class t_basic_smem_obj //backward compatibility typedef t_basic_smem_obj<t_def_thread_traits> t_smart_memory_object;
2007-01-17. Нормализация.
//////////////////////////////////////////////////////////////////////////////// //class t_basic_sobj template<class thread_traits> class t_basic_sobj { private: typedef t_basic_sobj<thread_traits> self_type; t_basic_sobj(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------ typedef thread_traits thread_traits_type; typedef typename thread_traits_type::int_type cnt_ref_type; protected: //inherited only --------------------------------------------- t_basic_sobj(); virtual ~t_basic_sobj(); public: virtual cnt_ref_type add_ref(); virtual cnt_ref_type release(); public: cnt_ref_type get_cntRef()const; private: cnt_ref_type m_cntRef; #ifndef NDEBUG protected: bool sobj_is_destroyed()const {return m_sobj_is_destroyed;} protected: bool m_sobj_is_destroyed; #endif };//class t_basic_sobj //backward compatibility typedef t_basic_sobj<t_def_thread_traits> t_smart_object; /////////////////////////////////////////////////////////////////////////////// //class t_basic_smem_obj template<class thread_traits,class Allocator> class t_basic_smem_obj:public t_basic_sobj<thread_traits> { private: typedef t_basic_smem_obj<thread_traits,Allocator> self_type; typedef t_basic_sobj<thread_traits> inherited; t_basic_smem_obj(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------- typedef typename inherited::cnt_ref_type cnt_ref_type; protected: t_basic_smem_obj(); virtual ~t_basic_smem_obj(); public: //t_basic_sobj interface ----------------------------------------- virtual cnt_ref_type release(); public: static void* operator new (size_t sz); static void operator delete (void* pv); };//class t_basic_smem_obj //backward compatibility typedef t_basic_smem_obj<t_def_thread_traits> t_smart_memory_object;
2007-08-07. Появился final_release. Вызывается при обнулении счетчика ссылок.
//////////////////////////////////////////////////////////////////////////////// //class t_basic_sobj template<class thread_traits> class t_basic_sobj { private: typedef t_basic_sobj<thread_traits> self_type; t_basic_sobj(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------ typedef thread_traits thread_traits_type; typedef typename thread_traits_type::int_type cnt_ref_type; protected: //inherited only --------------------------------------------- t_basic_sobj(); virtual ~t_basic_sobj(); public: virtual cnt_ref_type add_ref(); virtual cnt_ref_type release(); protected: virtual void final_release(); public: cnt_ref_type get_cntRef()const; private: cnt_ref_type m_cntRef; #ifndef NDEBUG protected: bool sobj_is_destroyed()const {return m_sobj_is_destroyed;} protected: bool m_sobj_is_destroyed; #endif };//class t_basic_sobj //backward compatibility typedef t_basic_sobj<t_def_thread_traits> t_smart_object;
2009-04-22. Ключевой момент. Появляется абстрактный интерфейс — t_basic_smart_interface. До релиза третьей версии провайдера еще 16 месяцев. В дальнейшем у t_smart_interface начали появляться собственные производные абстрактные интерфейсы. А t_basic_sobj и t_basic_smem_obj постепенно уходят на второй план.
//////////////////////////////////////////////////////////////////////////////// //class t_basic_smart_interface template<class tag_thread_traits> class t_basic_smart_interface { public: //typedefs ------------------------------------------------------ typedef tag_thread_traits thread_traits; typedef typename thread_traits::int_type cnt_ref_type; public: virtual cnt_ref_type add_ref()=0; virtual cnt_ref_type release()=0; };//class t_basic_smart_interface typedef t_basic_smart_interface<t_def_thread_traits> t_smart_interface; //////////////////////////////////////////////////////////////////////////////// //class t_basic_sobj template<class tag_thread_traits> class t_basic_sobj:public t_basic_smart_interface<tag_thread_traits> { private: typedef t_basic_sobj<tag_thread_traits> self_type; typedef t_basic_smart_interface<tag_thread_traits> inherited; t_basic_sobj(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------ typedef typename inherited::cnt_ref_type cnt_ref_type; protected: //inherited only --------------------------------------------- t_basic_sobj(); virtual ~t_basic_sobj(); public: virtual cnt_ref_type add_ref(); virtual cnt_ref_type release(); protected: virtual void final_release(); public: cnt_ref_type get_cntRef()const; private: cnt_ref_type m_cntRef; #ifndef NDEBUG protected: bool sobj_is_destroyed()const {return m_sobj_is_destroyed;} protected: bool m_sobj_is_destroyed; #endif };//class t_basic_sobj //backward compatibility typedef t_basic_sobj<t_def_thread_traits> t_smart_object; /////////////////////////////////////////////////////////////////////////////// //class t_basic_smem_obj template<class tag_thread_traits,class Allocator> class t_basic_smem_obj:public t_basic_sobj<tag_thread_traits> { private: typedef t_basic_smem_obj<tag_thread_traits,Allocator> self_type; typedef t_basic_sobj<tag_thread_traits> inherited; t_basic_smem_obj(const self_type&); self_type& operator = (const self_type&); public: //typedefs ------------------------------------------------------- typedef typename inherited::cnt_ref_type cnt_ref_type; protected: t_basic_smem_obj(); virtual ~t_basic_smem_obj(); public: //t_basic_sobj interface ----------------------------------------- virtual cnt_ref_type release(); public: static void* operator new (size_t sz); static void operator delete (void* pv); };//class t_basic_smem_obj //backward compatibility typedef t_basic_smem_obj<t_def_thread_traits> t_smart_memory_object;
2009-05-11. Нормализация — указываем __declspec(novtable).
//////////////////////////////////////////////////////////////////////////////// //class t_basic_smart_interface /// <summary> /// Base class of smart interface. /// </summary> template<class tag_thread_traits> class COMP_CONF_DECLSPEC_NOVTABLE t_basic_smart_interface { public: //typedefs ------------------------------------------------------ typedef tag_thread_traits thread_traits; typedef typename thread_traits::int_type cnt_ref_type; public: virtual cnt_ref_type add_ref()=0; virtual cnt_ref_type release()=0; };//class t_basic_smart_interface typedef t_basic_smart_interface<t_def_thread_traits> t_smart_interface;
Наши дни (2015-10-19). Похоже достигнуто идеальное описание этого интерфейса.
//////////////////////////////////////////////////////////////////////////////// //class t_smart_interface /// <summary> /// Base class of smart interface. /// </summary> class COMP_CONF_DECLSPEC_NOVTABLE t_smart_interface { public: virtual void add_ref()=0; virtual void release()=0; };//class t_basic_smart_interface
В процессе перекомпиляции провайдера нашел одно место, где проверялся результат вызова release:
/// Останов свободных потоков while(!m_free_threads.empty()) { task_thread_type* const thread(m_free_threads.head()); //поток не должен быть привязан к контроллеру // - все свободные потоки проходят процедуру отключения // см. task_thread_processor и add_free_task_thread assert(thread->m_task_controller==NULL); m_free_threads.remove(tag_thread_list_traits(),thread); thread->stop_thread(); //контролируем, что на поток больше никто не ссылается _VERIFY_EQ(thread->release(),0); }//while
Но это мелочь, которая была исправлена.
Следующим этапом, думаю, будет определение производного интерфейса с методом query_interface. Я уже несколько раз натыкался на то, что этого метода очень не хватает.
И в итоге приду к тому, что умные люди придумали еще в прошлом тысячелетии: IUnknown.