Rogue Wave banner
Previous fileTop of DocumentContentsIndex pageNext file
Essential Tools Module User's Guide

12.4 More on Storing and Retrieving RWCollectables

In Section 9.6.1, we saw how to save and restore the morphology or pointer relationships of a class using the following global functions:

When working with RWCollectables, it is useful to understand how these functions work. Here is a brief description.

When you call one of the left-shift << operators for any collectable object for the first time, an identity dictionary is created internally. The object's address is put into the dictionary, along with its ordinal position in the output file -- for example, first, second, sixth, etc.

Once this is done, a call is made to the object's virtual function saveGuts(). Because this is a virtual function, the call will go to the definition of saveGuts() used by the derived class. As we have seen, the job of saveGuts() is to store the internal components of the object. If the object contains other objects inheriting from RWCollectable, the object's saveGuts() calls operator<<() recursively for each of these objects.

Subsequent invocations of operator<<() do not create a new identity dictionary, but store the object's address in the already existing dictionary. If an address is encountered which is identical to a previously written object's address, then saveGuts() is not called. Instead, a reference is written that this object is identical to some previous object.

When the entire collection is traversed and the initial call to saveGuts() returns, the identity dictionary is deleted and the initial call to operator<<() returns.

The function operator>>() essentially reverses this whole process by calling restoreGuts() to restore objects into memory from a stream or file. When encountering a reference to an object that has already been created, it merely returns the address of the old object rather than asking the RWFactory to create a new one.

Here is a more sophisticated example of a class that uses these features:

In the above example, the class Tangle implements a circularly linked list. What happens? When function operator<<() is called for the first time for an instance of Tangle, it sets up the identity dictionary as described above, then calls Tangle's saveGuts(), whose definition is shown above. This definition stores any member data of Tangle, then calls operator<<() for the next link. This recursion continues on around the chain.

If the chain ends with a nil object (that is, if nextTangle is zero), then operator<<() notes this internally and stops the recursion.

On the other hand, if the list is circular, then a call to operator<<() is eventually made again for the first instance of Tangle, the one that started this whole chain. When this happens, operator<<() will recognize that it has already seen this instance before and, rather than call saveGuts() again, will just make a reference to the previously written link. This stops the series of recursive calls and the stack unwinds.

Restoration of the chain is done in a similar manner. A call to:

can create a new object off the heap and return a pointer to it, return the address of a previously read object, or return the null pointer. In the last two cases, the recursion stops and the stack unwinds.

Previous fileTop of DocumentContentsIndex pageNext file

©2004 Copyright Quovadx, Inc. All Rights Reserved.
Rogue Wave and SourcePro are registered trademarks of Quovadx, Inc. in the United States and other countries. All other trademarks are the property of their respective owners.
Contact Rogue Wave about documentation or support issues.