Столкнулся с такой вот проблемой. Есть головной exe и dll. Есть собственный умный указатель, следующего вида:
template <typename T>
class CtSmartLink
{
private:
typedef CtValues<T*, int> CtdRefCount; // CtValues - обертка для std::map
static CtdRefCount * m_pRefCount; // статический указатель на map, где храним кол-во ссылок
T * m_pLink; // указатель на свой объект
protected:
int AddRef(T * a_p);
int Release(T * a_p);
void Destroy(T * a_p);
void Alloc();
void Free();
public:
CtSmartLink<T> ();
CtSmartLink<T> (T * a_p);
CtSmartLink<T> (const CtSmartLink<T> & a_Src);
CtSmartLink<T> (const CtSmartLink<T> * a_pSrc);
virtual ~CtSmartLink ();
CtSmartLink<T> & operator = (T * a_p);
CtSmartLink<T> & operator = (const CtSmartLink<T> * a_pSrc);
CtSmartLink<T> & operator = (const CtSmartLink<T> & a_Src);
T * operator -> (void);
bool operator ! () const;
};
//==============================================================================
template <typename T>
void CtSmartLink<T>::Alloc()
{
if (m_pRefCount == NULL) // если еще никто не создал map, то создаем
{
m_pRefCount = new CtdRefCount;
if (m_pRefCount == NULL)
throw std::invalid_argument("Out of memory. CtSmartLink<T>::Alloc().");
}
}
//------------------------------------------------------------------------------
template <typename T>
void CtSmartLink<T>::Free()
{
if (m_pRefCount != NULL)
{
if (m_pRefCount->Size() < 1) // если в map больше нет элементов, значит он больше не нужен
{
delete m_pRefCount;
m_pRefCount = NULL;
}
}
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T>::CtdRefCount * CtSmartLink<T>::m_pRefCount = NULL;
template <typename T>
CtSmartLink<T>::CtSmartLink(T * a_p)
{
Alloc();
m_pLink = a_p;
AddRef(m_pLink);
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T>::CtSmartLink()
{
Alloc();
m_pLink = NULL;
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T>::CtSmartLink(const CtSmartLink<T> & a_Src)
{
Alloc();
m_pLink = a_Src.m_pLink;
AddRef(m_pLink);
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T>::CtSmartLink(const CtSmartLink<T> * a_pSrc)
{
Alloc();
m_pLink = a_pSrc->m_pLink;
AddRef(m_pLink);
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T>::~CtSmartLink()
{
Release(m_pLink);
Free();
}
//------------------------------------------------------------------------------
template <typename T>
int CtSmartLink<T>::AddRef(T * a_p)
{
if (m_pRefCount->isSet(a_p))
(*m_pRefCount)[a_p]++;
else
m_pRefCount->Set(a_p, 1);
size_t nRefCount = (*m_pRefCount)[a_p];
return nRefCount;
}
//------------------------------------------------------------------------------
template <typename T>
int CtSmartLink<T>::Release(T * a_p)
{
int nRefCount = -1;
if (m_pRefCount->isSet(a_p))
{
(*m_pRefCount)[a_p]--;
nRefCount = (*m_pRefCount)[a_p];
if (nRefCount < 1)
Destroy(a_p);
}
return nRefCount;
}
//------------------------------------------------------------------------------
template <typename T>
void CtSmartLink<T>::Destroy(T * a_p)
{
if (m_pRefCount->isSet(a_p))
{
if (a_p != NULL)
{
delete a_p;
m_pLink = NULL;
}
m_pRefCount->Delete(a_p);
}
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T> & CtSmartLink<T>::operator = (const CtSmartLink<T> * a_pSrc)
{
m_pRefCount = a_pSrc->m_pRefCount;
if (m_pLink != a_pSrc->m_pLink)
{
Release(m_pLink);
m_pLink = a_pSrc->m_pLink;
AddRef(m_pLink);
}
return (*this);
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T> & CtSmartLink<T>::operator =(const CtSmartLink<T> & a_Src)
{
if (m_pLink != a_Src.m_pLink)
{
Release(m_pLink);
m_pLink = a_Src.m_pLink;
AddRef(m_pLink);
}
return (*this);
}
//------------------------------------------------------------------------------
template <typename T>
CtSmartLink<T> & CtSmartLink<T>::operator =(T * a_p)
{
if (m_pLink != a_p)
{
Release(m_pLink);
m_pLink = a_p;
AddRef(m_pLink);
}
return (*this);
}
//------------------------------------------------------------------------------
template <typename T>
T * CtSmartLink<T>::operator -> (void)
{
return m_pLink;
}
//------------------------------------------------------------------------------
template <typename T>
bool CtSmartLink<T>::operator ! () const
{
return (m_pLink == NULL);
}
//------------------------------------------------------------------------------
В dll есть парсер XML, следующего вида:
// класс узел
class CcXMLNode : virtual public iXMLNode
{
private:
CtSmartLink<iXMLNode> CreateNode()
{
CtSmartLink<iXMLNode> Node = dynamic_cast<iXMLNode *> (new CcXMLNode());
return Node;
}
...
public:
virtual ~CcXMLNode();
virtual CtSmartLink<iXMLNode> GetNode(const nsCommon::String & a_sName)
{
...
CtSmartLink<iXMLNode> FoundNode = CreateNode();
...
return FoundNode;
}
...
};
class CcXML : virtual public iXML
{
private:
CtSmartLink<iXMLNode> m_RootNode; // корневой узел
public:
CcXML();
virtual ~CcXML();
virtual CtSmartLink<iXMLNode> RootNode();
...
};
В головном exe начинаем это дело использовать:
...
//загрузили dll
...
CcXML XML;
CtSmartLink<iXMLNode> RootNode = XML.RootNode();
// усе нормально нода пришла.
CtSmartLink<iXMLNode> MyNode; // и вдруг нам понадобилось сделать так
И начинаются проблемы... Сработал конструктор по-умолчанию для MyNode, заходим отладчиком и видим, что static CtdRefCount * m_pRefCount у него другой нежели для умного указателя в dll и равен NULL, естественно видя NULL он создает map еще раз.
По окончанию работы вообще происходит странность : Срабатывает деструктор объекта MyNode -> сносит свой map. Затем пошел деструктор CcXML::m_RootNode. И тут выясняется что его map тоже уже НЕТУ! Access при попытке выполнить if (m_pRefCount->isSet(a_p)).
Отсюда вопрос 1: map c количеством ссылок на объеты для CtSmartLink'ов созданных в exe и dll все таки одинаковый или разный ?
вопрос 2: как еще можно решить данную пробему ?
P.S. Кривое решение впринципе есть. Это делать данный map в головном exe, а dll давать на него ссылку.