Copying classes is a common software procedure. It happens every time a copy constructor is applied, or whenever a process needs a copy to work on. Copying value-based collection classes is straightforward. But special considerations arise in copying reference-based classes, and we deal with them here.
What happens when you make a copy of a reference-based collection class, or any class that references another object, for that matter? It depends which of the two general approaches you choose: shallow copying or deep copying.
A shallow copy of an object is a new object whose instance variables are identical to the old object. For example, a shallow copy of a Set has the same members as the old Set, and shares objects with the old Set through pointers. Shallow copies are sometimes said to use reference semantics.
The copy constructors of all reference-based Rogue Wave collection classes make shallow copies.
A deep copy of an object is a new object with entirely new instance variables; it does not share objects with the old. For example, a deep copy of a Set not only makes a new Set, but also inserts items that are copies of the old items. In a true deep copy, this copying is done recursively. Deep copies are sometimes said to use value semantics.
Note that some reference-based collection classes have a copyContentsTo() member function that returns a new object with entirely new instance variables. This copying is not done recursively, and the new instance variables are shallow copies of the old instance variables.
Here's a graphical example of the differences between shallow and deep copies. Imagine Bag, an unordered collection class of objects with duplicates allowed, that looks like this before a copy :
Making a shallow copy and a deep copy of Bag would produce the following results:
You can see that the deep copy copies not only the bag itself, but recursively all objects within it.
The copying approach you choose is important. For example, shallow copies can be useful and fast, because less copying is done, but you must be careful because two collections now reference the same object. If you delete all the items in one collection, you will leave the other collection pointing into nonsense.
You also need to consider the approach when writing an object to disk. If an object includes two or more pointers or references to the same object, it is important to preserve this morphology when the object is restored. Classes that inherit from RWCollectable inherit algorithms that guarantee to preserve an object's morphology. You'll see more on this in Section 14.
Let us now contrast the results of copying the reference-based collection with the value-based collection. Consider the class:
RWTValOrderedVector<RWCString>
that is, an ordered vector template instantiated for RWCString. In this case, each string is embedded within the collection. When a copy of the collection class is made, not only the collection class itself is copied, but also the objects in it. This results in distinct new copies of the collected objects: