ProgramArtist
April 9th, 2008, 08:34 AM
Hi,
Maybe this is a c++ question but I guess it is general (although I encountered it using MS VC++ 6.0).
I created a class (and many classes derived from that) with reference counting and auto-freeing (just like a garbage collection).
If I assign a pointer to a CFooReferenceCounting object I call IncRefCount() and assigning any other value (incl. NULL) I'll always call DecRefCount(). This works fine since I overloaded all used operators in the FooReferenceCounting-holding class (it's my own TVARIANT class for scripting purposes).
I added the code (actually some snippets...) that you might understand what I have done.
I encountered the following problem:
If I declare a class CFoo_Very_Complex as a derivate of CFooReferenceCounting with an attribut of type
TVARIANT or TVARIANT* it is possible that I assign the value of this to this attribut.
Now the auto-freeing mechanism is broken since that CFooReferenceCounting will never be freed since there is always
another (sic!) element (actually the element itself!) pointing to it.
Has anyone any idea of a clean and safe solution for this?
Of course I can (e.g. in the app's idle) check for such circle-pointings ... but: Is this nice?
(Please note: If this could be the solution it has to be done recursively since I can have an object A
pointing to B pointing to C pointing to A again...
class CFooReferenceCounting:
// using MS VC 6.0
#include <afxtempl.h> // for the CList class template
class CFooReferenceCounting
{
public:
CFooReferenceCounting(){m_bAutoDelete = TRUE;m_iRefCount=0;};
virtual ~CFooReferenceCounting();
int GetRefC(){return m_iRefCount;};
virtual void IncRefC(TVARIANT* pTV);
virtual void DecRefC(TVARIANT* pTV);
protected:
BOOL m_bAutoDelete;
int m_iRefCount;
CList<tagTVARIANT*,tagTVARIANT*> m_refs;
}
CFooReferenceCounting::~CFooReferenceCounting()
{
if (GetRefC())
{
// set all references to PTR/NULL
m_bAutoDelete = FALSE; // to avoid suicide inside this function
POSITION pos = m_refs.GetHeadPosition();
while (pos)
{
tagTVARIANT* pTV = m_refs.GetNext(pos);
pTV->SetPtr(NULL); // includes a call to DecRefC of ourself
}
}
ASSERT(GetRefC()==0);
}
void CFooReferenceCounting::IncRefC(TVARIANT* pTV)
{
m_iRefCount++;
m_refs.AddTail(pTV);
}
void CFooReferenceCounting::DecRefC(TVARIANT* pTV)
{
m_iRefCount--;
POSITION pos = m_refs.Find(pTV);
ASSERT(pos);
if (pos)
{
m_refs.RemoveAt(pos);
}
if (m_iRefCount==0)
{
if (m_bAutoDelete)
{
delete [] this; // suicide !
}
}
}
The TVARIANT struct/class:
class CFooReferenceCounting; // forwarded here ...
typedef struct tagTVARIANT
{
int tv_iType;
int tv_iVal;
CString tv_sVal;
CFooReferenceCounting::* tv_pVal;
...
tagTVARIANT& operator=(tagTVARIANT& tvSource);
...
other operands are overwritten the same way of course ...
...
} TVARIANT;
tagTVARIANT& tagTVARIANT::operator=(tagTVARIANT& tvSource)
{
if (tv_iType==TVTYPE_PTR) tvSource.tv_pVal->DecRefC(this);
this->tv_iType = tvSource.tv_iType;
this->tv_iVal = tvSource.tv_iVal;
this->tv_fVal = tvSource.tv_fVal;
this->tv_pVal = tvSource.tv_pVal;
this->tv_sVal = tvSource.tv_sVal;
if (tv_iType==TVTYPE_PTR) tvSource.tv_pVal->IncRefC(this);
return *this;
}
...
With regards
Programartist
Ingo Bochmann
Maybe this is a c++ question but I guess it is general (although I encountered it using MS VC++ 6.0).
I created a class (and many classes derived from that) with reference counting and auto-freeing (just like a garbage collection).
If I assign a pointer to a CFooReferenceCounting object I call IncRefCount() and assigning any other value (incl. NULL) I'll always call DecRefCount(). This works fine since I overloaded all used operators in the FooReferenceCounting-holding class (it's my own TVARIANT class for scripting purposes).
I added the code (actually some snippets...) that you might understand what I have done.
I encountered the following problem:
If I declare a class CFoo_Very_Complex as a derivate of CFooReferenceCounting with an attribut of type
TVARIANT or TVARIANT* it is possible that I assign the value of this to this attribut.
Now the auto-freeing mechanism is broken since that CFooReferenceCounting will never be freed since there is always
another (sic!) element (actually the element itself!) pointing to it.
Has anyone any idea of a clean and safe solution for this?
Of course I can (e.g. in the app's idle) check for such circle-pointings ... but: Is this nice?
(Please note: If this could be the solution it has to be done recursively since I can have an object A
pointing to B pointing to C pointing to A again...
class CFooReferenceCounting:
// using MS VC 6.0
#include <afxtempl.h> // for the CList class template
class CFooReferenceCounting
{
public:
CFooReferenceCounting(){m_bAutoDelete = TRUE;m_iRefCount=0;};
virtual ~CFooReferenceCounting();
int GetRefC(){return m_iRefCount;};
virtual void IncRefC(TVARIANT* pTV);
virtual void DecRefC(TVARIANT* pTV);
protected:
BOOL m_bAutoDelete;
int m_iRefCount;
CList<tagTVARIANT*,tagTVARIANT*> m_refs;
}
CFooReferenceCounting::~CFooReferenceCounting()
{
if (GetRefC())
{
// set all references to PTR/NULL
m_bAutoDelete = FALSE; // to avoid suicide inside this function
POSITION pos = m_refs.GetHeadPosition();
while (pos)
{
tagTVARIANT* pTV = m_refs.GetNext(pos);
pTV->SetPtr(NULL); // includes a call to DecRefC of ourself
}
}
ASSERT(GetRefC()==0);
}
void CFooReferenceCounting::IncRefC(TVARIANT* pTV)
{
m_iRefCount++;
m_refs.AddTail(pTV);
}
void CFooReferenceCounting::DecRefC(TVARIANT* pTV)
{
m_iRefCount--;
POSITION pos = m_refs.Find(pTV);
ASSERT(pos);
if (pos)
{
m_refs.RemoveAt(pos);
}
if (m_iRefCount==0)
{
if (m_bAutoDelete)
{
delete [] this; // suicide !
}
}
}
The TVARIANT struct/class:
class CFooReferenceCounting; // forwarded here ...
typedef struct tagTVARIANT
{
int tv_iType;
int tv_iVal;
CString tv_sVal;
CFooReferenceCounting::* tv_pVal;
...
tagTVARIANT& operator=(tagTVARIANT& tvSource);
...
other operands are overwritten the same way of course ...
...
} TVARIANT;
tagTVARIANT& tagTVARIANT::operator=(tagTVARIANT& tvSource)
{
if (tv_iType==TVTYPE_PTR) tvSource.tv_pVal->DecRefC(this);
this->tv_iType = tvSource.tv_iType;
this->tv_iVal = tvSource.tv_iVal;
this->tv_fVal = tvSource.tv_fVal;
this->tv_pVal = tvSource.tv_pVal;
this->tv_sVal = tvSource.tv_sVal;
if (tv_iType==TVTYPE_PTR) tvSource.tv_pVal->IncRefC(this);
return *this;
}
...
With regards
Programartist
Ingo Bochmann