An example of a container might be an array of objects, or the stack class that we have met in various exercises.
Types of Container
A container that contains objects of a single type is said to be homogenous.
A container that contains objects of a variety of types is termed heterogeneous.
In C++, a heterogeneous container will usually contain objects that are derived from a common base class; this allows programs to iterate through the container using base class member functions.
Containers may store objects by reference or by value. If a container stores only copies of objects, that container is said to have value semantics. If on the other hand the container stores pointers to the objects that it is intended to store, the container is said to have reference semantics.
Containers with value semantics exhibit the following behaviour:
- No object exists in two or more containers (there is no sharing).
- Copies of objects are stored in the container. When an object is stored in the container a new object is created inside the container.
- When the container is destroyed, the objects it contains are also destroyed.
Containers with reference semantics behave as follows:
- An object may be "in" two or more containers, as each container contains only a reference to the object.
- Placing an object into a container does not involve copying the object.
- When the container is destroyed, the objects in the container are not destroyed.
There is a problem when an object that is in a reference container is destroyed. Unless some mechanism exists to notify all containers, the container will be left with a dangling reference.
The ideal container, from a programming point of view, is one which is homogenous, with value semantics. This form is directly supported by the use of C++ templates.
Containers with Iterators
An iterator allows clients of the container class to step through the objects in the container, one at a time. The iterator is usually defined as a friend class and declared as a separate object. Typical functions provided by the iterator class include:
at_end to indicate when there are no more objects to be examined.
current to return the current object in the container.
first to return the first object in the container.
last to return the last object in the container.
next to advance the iterator to the next object in the container.
restart to reset the iterator to the first object in the container.
This is not a definitive list. For example it only supports traversing the container in one direction.
When a container is changed by the addition or removal of an object, the iterator's position may be invalidated. Thus the container itself must be aware of all active iterator objects so that they may be notified. Similarly, if an iterator is able to change a container, it must notify all other iterators.