wxXml2Wrappers and reference counting

wxXml2Wrapper-derived classes does not use a full Copy-On-Write technique: when copying a wxXml2Wrapper you just create a new wxXml2Wrapper (which requires few bytes and thus this is a very fast operation) which wraps the same libxml2 structure of the original wxXml2Wrapper.

Consider the following code:









    //! 
The result won't be a document with a root named "root_of_doc" but a document with "myroot" as root's name. This is because deep copies are never performed, unlike, for example, in wxString's COW system where the string is shared until a non-const function is called. The libxml2 structures are always shared with wxXml2Wrapper. This is required since the wrappers around libxml2 structures are created on the fly by the wrapper's getters: this is why you'll see only functions returning objects and not references to objects.

Since the underlying libxml2 structures are always shared, a reference count system is required to avoid things like:










    //! 
Without reference counting, the destructor of an xml2 wrapper cannot know if other instances of xml wrappers are sharing the same structure. Performing a deep-copy in the copy constructor would be a problem: XML nodes are all linked together and unlinking a node and then inserting a new one is not so easy (especially for all types of nodes).

The only solution is to use a reference count; but the reference count must be stored in the wrapped structure. How wxXml2Wrapper handle this problem ? Well, all libxml2 structure has a VOID* field called "_private" which can be safely used by external functions to hold user contents. The GetPrivate() function casts that pointer to a reference to a integer so that it can be used as an int instead of a pointer to void.

With reference counting the destructor of a wxXml2Wrapper knows if it is the only instance of that structure (and in this case it should free the structure) or if other wxXml2Wrappers still own that structure (and in this case it only decreases the refcount):











    //! 

Anyway there is another thing to consider: libxml2 implements "recursive destruction". When a node is destroyed, all its children are too. This means that we must also be careful not to break libxml2 memory representation destroying a node's child when it's still linked to its parent. Precisely, when a node (but also a property, a dtd, a namespace...) is part of a wider XML tree, we must *never* delete the node when the relative wxXml2Wrapper is destroyed. This is why all wxXml2Wrappers must implement the IsUnlinked() function: the DestroyIfUnlinked() function uses it to find when nodes are unlinked from a wider tree and thus must be destroyed by xml2 wrapper. However, this rises another problem ! Consider the example below:




















    //! 

How can we solve this problem ? One solution could be not only to check if the node is unlinked but also to check if all children refcounts are set to zero, in each node destructor. However, I did not implement this solution because it can make all wxxml2 wrappers very slow: wxXml2Nodes are continuosly created & destroyed. The solution I adopted is simply to force the user (you!) to call the wxXml2Wrapper::DestroyIfUnlinked() function in the right order. This approach is not more restrictive of the approach used, for example, by libxml++ which uses pointers and thus require the DELETE calls to be in the right order. The example above must thus be rewritten as:




















    //! 
So, as general rule, when using wxXml2Wrapper-derived classes, you must always call the wxXmlWrapper::DestroyIfUnlinked functions in the right order: first the DestroyIfUnlinked functions of all children and then, as last, the DestroyIfUnlinked function of the node containing all the others.
Generated on Thu Sep 28 14:58:01 2006 for wxXml2 by  doxygen 1.4.7