Design Question Pt-1: Forcing const pointers and reference counting in graph structure
Hi,
I am trying to design a compact (scene) graph library. It has nothing
to do with actual rendering of a scene whatsoever but strictly dealing
with logical relationship between objects.
I didn't think about it thoroughly, and as a matter of fact there is
no real code at the moment. I didn't want to begin writing code before
thinking enough about it. If there is a fundamental flaw in the idea/
design, then there is no point to waste my time.
Traversing graph is the most important part and I consider using
parallel algorithms. To ease this operation, I thought about returning
a const pointer after instantiating objects. I thought this approach
would enforce a stricter policy for mutating objects, and increase
chance of dealing with read-only objects, make it easy to detect
races. To access mutator, caller should use MutableObject<T> for
"attaching" to the object to mutate.
The first problem I thought about was reference counting. All objects
are reference counted. Enough with long story, here is what I thought
(only theory, never compiled):
// reference counter, top in inheritance hierarchy
class RefCounted
{
volatile long m_cref;
public:
long AddRef() { return atomic_increment(&m_cref); }
long Release()
{
long cref = atomic_decrement(&m_cref);
if (0 == cref) delete this;
return cref;
}
protected:
virtual ~RefCounted() { }
};
// factory that instantiates object and return const pointer
template<typename T>
struct ObjectFactory
{
static const T* Create()
{
return new T;
}
};
// to prevent use of operator new directly
class ConstObject
{
template<typename T> friend struct ObjectFactory<T>;
protected:
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*);
// ... other overloads
};
// generic object class; holds basic information about an object
class Object : public RefCounted, public ConstObject
{
template<typename T>
friend class MutableObject<T>;
void AttachMutator(); // some kind of mutex?
void DetachMutator(); // unlocking the mutex?
public:
const std::string& GetName() const;
void SetName(const std::string&);
};
// idea stolen from Microsoft's CComPtr
template<typename T>
class NoAddRefRelease : public T
{
private:
long AddRef();
long Release();
};
// RefObj is intrusive smart pointer
template<typename T>
class RefObj
{
T* m_p;
public:
explicit RefObj(const T* pT = NULL)
: m_p(const_cast<T*>(pT)
{
if (m_p) m_p->AddRef();
}
NoAddRefRelease<T>* operator->() { return (NoAddRefRelease<T>*>)
m_p; } // see below note
NoAddRefRelease<T>* get() const { return (NoAddRefRelease<T>*)m_p; }
void reset(T* pT = NULL)
{
if (m_p == pT) return;
if (m_p) m_p->Release();
if (pT) pT->AddRef();
m_p = pT;
}
};
// a node in graph
class Node : public Object
{
protected:
~Node();
};
To deal with RefObj<T> and reference counting, I thought may be
ObjectFactory<T>::Create returns a RefObj<T> directly, and, RefObj's
operator->() and get() returns a const NoAddRefRelease<T>*.
I would like to achieve following:
Node* pNode = new Node; // error
RefObj<Node> spNode = ObjectFactory<T>::Create();
spNode->SetName("myName"); // error
spNode.get()->SetName("myName"); // error
delete spNode.get(); // error
MutableObject<Node> mutNode(spNode);
mutNode->SetName("myName"); // ok
Therefore, MutableObject may look like:
template<typename T>
class MutableObject
{
T* m_p;
public:
explicit MutableObject(RefObj<T>& rObj)
: m_p(rObj.get())
{
m_p->AttachMutator(this);
}
~MutableObject() { m_p->DetachMutable(); }
NoAddRefRelease<T>* operator->() { return m_p; }
};
This requires changes in RefObj<T> to allow access from
MutableObject<T> to its m_p or a private get() method which will
return a non-const qualified T*.
This is entirely on the paper, may be ridiculous, and I am not sure
how practical it is, and that's why I wanted to bring this up here for
discussion.
I'd be very happy, if you share your valuable feedback.
Regards,
Ismail
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]