Object visiting

The CSpace garbage collector requires every object in the CSpace which implements interface IObject to visit all outgoing pointers to other objects in the CSpace in its implementation of the VisitObjects() member function.

Visiting outgoing pointers

The insertion operator makes is easy for a class to implement VisitObjects(). Typically it's as simple as "listing" all the data members. For example


$class Automobile isa IAutomobile
{
    void VisitObjects(IObjectVisitor& v) const
    {
        v << engine << wheels;
        BaseClass::VisitObjects(v);
    }

    ptr<IEngine> engine;
    xvector<ptr<IWheel> > wheels;
};

The framework allows the standard C++ library std::pair, std::vector, std::deque, std::list, std::set and std::map members to be directly "visited". The template implementations of the insertion operator simply recurse into the elements.

Given that std::map elements are std::pair objects and it is common for only one of the elements to be an IObject pointer, the framework provides "do nothing" implementations for visiting the basic types such as bool, char, short, int, long, float, double and xstring.

An important type of pointer is the pref<T> which represents a pointer to a persistent object. These should also be visited.

If the programmer forgets to implement VisitObjects(), or fails to visit all outgoing IObject pointers then there is a risk that objects that are in fact reachable will be collected during the next sweep phase. This will typically lead to access violations.

Dealing with non-IObject classes

Non-IObject classes can be written that contain IObject pointers. Consider the following example:


struct Node
{
    ptr<IObject> left;
    ptr<IObject> right;
};

In these cases it is best to write an insertion operator like this:


inline IObjectVisitor& operator<<(IObjectVisitor& v, const Node& node)
{
    v << node.left << node.right;
    return v;
}

Consider that Node is stored within another non-IObject class called Page. It is easy to write the insertion operation for Page as follows


struct Page
{
    xvector<Node> nodes;
};

inline IObjectVisitor& operator<<(IObjectVisitor& v, const Page& page)
{
    v << page.nodes;
    return v;
}

Eventually non-IObject classes must be reachable from an IObject (or else they are garbage and can be collected). At this point they will be visited in the normal way - i.e. from an implementation of VisitObjects().


$class X isa IObject
{
    void VisitObjects(IObjectVisitor& v) const
    {
        v << page;
    }
    Page page;
};