Dynamic references can be serialised, provided a few properties are known about the data structure they make up. There is no way of knowing whether standard pointer actually points to a real object, nor how many. However, since collections of objects are more conveniently handled by standard containers, and since no object can pointed to by the value 0 (or NULL), we can determine these things if the programmer follows a protocol whereby a pointer either references at a single object, or is NULL. Using a smart pointer additionally enforces this protocol. We call this the treenode or graphnode protocol, depending on whether the referenced data structure has cycles or not.
By default, packing a pointer raises an exception. However, this
behavior is changed either by specifying a given type obeys the
treenode or graphnode protocol using the treenode
pragma or graphnode pragma
respectively. Alternatively, the pack_t::ptr_flag
can be set to
the values TREE
or GRAPH
respectively.
What happens in this case, is that special graph serialisation
algorithms defined in pack_graph.h
are called that ensure graph
objects are serialised or deserialised correctly. For deserialisation,
new objects must be created to store the node contents. References to
these objects are placed in the alloced
member
of the pack_t
buffer object. These newly created objects are
destroyed when the buffer object is destroyed, unless a copy of the
alloced
vector is made first. Conversely, the objects can be
destroyed without destroying the buffer by clearing the alloced
vector. Individual objects can be destroyed by simply erasing them
(assuming you know which ones!).
pack_graph is a recursive depth-first algorithm, that could
potentially blow up the stack if the recursion depth is not
limited. The recursion limit can be specified using
pack_t::recur_max
. pack_graph restarts the
algorithm once the recursion limit is reached.
The pack_graph
algorithm can also be applied to smart pointers
or other reference types. An example is the ref
smart pointer
provided with Classdesc. For your smart pointer class T, you will need to provide an Alloc<T>
class with an operator()(pack_t* buf, T& x)
that returns a
newly allocated object referenced by x. The buf
object is there
if you wish to use the alloced mechanism.