CopperSpice API
1.9.2
|
CopperSpice provides several container classes which use templates to define the data types of the stored elements. QVector<QString> is an example of a container which stores strings. To store a set of integers without duplicates use QSet<int>. Containers can be used as a value in another container. For example, QMap<QString, QList<int>> defines a QMap where the key is a QString and the value is a QList<int>.
The CopperSpice sequential containers and associative containers are shown in the table below. The container classes are implemented using the C++ standard library (STL). The API for our containers has been extended to support the full STL style syntax while maintaining all of the existing API.
Class | Based On | Description |
---|---|---|
QList<T> | std::deque | Stores a list of elements of a given data type which can be accessed by an index |
QLinkedList<T> | std::list | Better performance than QList when inserting in the middle of a large list, iterators pointing to an item in a QLinkedList remain valid as long as the item exists |
QStringList | Inherits from QList<QString> | Provides several methods which only pertain to strings |
QQueue<T> | Implemented using QList | Provides "first in, first out" (FIFO) semantics |
QStack<T> | Implemented using QVector | Provides "last in, first out" (LIFO) semantics |
QSet<T> | std::unordered_set | Similar to QHash except only storing keys, duplicates not allowed, fast lookups |
QFlatMap<K, V> | Implemented using QVector | Similar to QMap, uses less memory, good choice when the number of elements is small |
QMap<K, V> | std::map | Stores a key, value pair, slower when the number of elements is large |
QMultiMap<K, V> | std::multimap | Stores a key, value pair, duplicate keys are allowed |
QHash<K, V> | std::unordered_map | Stores a key, value pair, significantly faster than QMap |
QMultiHash<K, V> | std::unordered_multimap | Stores a key, value pair, duplicate keys are allowed |
QVector<T> | std::vector | Stores elements in contiguous memory |
The values stored in a container should be default constructible and copy constructible. If the type T meets these requirements then every method in the container class can be invoked. If you use a T which does not support both of these constructors, calls to some of the container methods will not compile when invoked.
Basic data types such as int
, double
, pointer types, and built in types such as QString, QDate, and QTime are all valid as the T. Data types like QObject or any subclass like QWidget, QDialog, QTimer, are not copy constructible and therefore data of these types should never be stored in a container. As an alternative, a pointer to a QObject or any subclass can be stored in any CopperSpice container class.
The following is an example of a custom data type which has a default constructor and copy constructor. The Employee class can be used as the T for any container.
If a default constructor, copy constructor, or an assignment operator is not declared the compiler will provide a default implementation when possible. The compiler generated implementation of a default constructor creates the object by calling the default constructor for the parent class. The default implementation of the copy constructor will make a copy of each class member.
In the following example no constructors or assignment constructors are declared so the compiler will generate the appropriate methods. This data type can be used as the T for any container.
When a new object is created and no data is passed to the constructor, a default constructor is called if one is available. There are two ways to default construct an object.
The object will be default initialized if no parameter list is passed. The following are are examples of default initialized objects.
For primitive types like int, double, pointer types, and char, default initialization creates an uninitialized value. Reading a default initialized value of a primitive type is undefined behavior. Ensure all primitive types in your application are initialized to a defined value before reading.
The other approach is called value initialized and this occurs when an empty parameter list is passed.
For primitive types like int, double, pointer types, and char, value initialization creates an value of zero or nullptr. Reading a value initialized value of a primitive type is valid.
The following table shows the default value for the most common data types.
Data Type | Default Initialized | Value Initialized |
---|---|---|
char | uninitialized | \0 |
int, float, double | uninitialized | 0 |
pointer | uninitialized | nullptr |
QDate | invalid date | invalid date |
QString | empty | empty |
QTime | invalid time | invalid time |
QUrl | empty | empty |
QUUid | all zeros | all zeros |
In the following example data1 will be constructed with twenty default initialized elements. Each element will be a uninitialized int. The elements for data2 will be uninitialized pointers.
In the following example data3 will be constructed with five default initialized elements. Each element will contain a valid empty string.
If the T is a QDate the default initialized elements will be set to an invalid date by the default constructor for QDate.
The CopperSpice containers provide operator<<() and operator>>() function for reading and writing data using a QDataStream. This requires the type T stored in the container must also support the operator<<() and operator>>() functions.
The following is an example using "struct Movie".
To iterate or navigate over every element of a container it is better to use a "range based for loop" whenever possible. The following example shows the correct syntax.
There are four other special purpose container classes worth mentioning. They have STL style iterators and can be used with the C++ range based for loop syntax.