The general objective of collection classes, called collections for short, is to store and retrieve objects. In fact, you can classify collection classes according to how they store objects. Value-based collections store the object itself; reference-based collections store a pointer or reference to the object. The difference between the two will influence how you use some features of collection classes in Tools.h++.
Value-based collection classes are simpler to understand and manipulate. You create a linked list of integers or doubles, for example, or a hash table of shorts. Stored types can be more complicated, like the RWCStrings, but the important point is that they act just like values, even though they may contain pointers to other objects. When an object is inserted into a value-based collection class, a copy is made. The procedure is similar to C's pass-by-value semantics in function calls.
In a reference-based collection class, you store and retrieve pointers to other objects. For example, you could create a linked list of pointers to integers or doubles, or a hash table of pointers to RWCStrings.
Let's look at two code fragments that demonstrate the difference between the value-based and the reference-based procedures:
Value-based Example | Reference-based Example |
/* A vector of RWCStrings: */ RWTValOrderedVector<RWCString> v; RWCString s("A string"); v.insert(s); |
/* A vector of pointers to RWCStrings: */ RWTPtrOrderedVector<RWCString> v; RWCString* p = new RWCString("A string"); v.insert(p); |
Both code fragments insert an RWCString into vector v. In the first example, s is an RWCString object containing "A string". The statement v.insert(s) copies the value of s into the vector. The object that lies within the vector is distinct and separate from the original object s. In the second example, p is a pointer to the RWCString object. When the procedure v.insert(p) is complete, the new element in v will refer to the same RWCString object as p.
A reference-based collection can be very efficient because pointers are small and inexpensive to manipulate. However, with a reference-based collection, you must always remember that you are responsible for memory management: the creation, maintenance, and destruction of the actual objects themselves. If you create two pointers to the same object and prematurely delete the object, you'll leave the second pointer pointing into nonsense. By the same token, you must never insert a nil pointer into a reference-based collection, since the collection has methods which must dereference its contained values.
Despite the added responsibility, don't avoid reference-based collections when you need them. Tools.h++ classes have member functions to help you, and in most cases, the ownership of the contained objects is obvious anyway. You should choose a reference-based collection if you need performance and size advantages: here the size of all pointers is the same, allowing a large degree of code reuse. Also choose the reference-based collection if you just want to point to an object rather than contain it (a set of selected objects in a dialog list, for example). Finally, for certain heterogeneous collections, the reference-based approach may be the only one viable.