Эволюция базового интерфейса
На самом нижнем уровне 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.