Qt logo


Collection Classes


A collection class is a class that can contain a number of items in a certain data structure and perform operations on the contained items; insert, remove, find etc.

Qt has many collection classes:

Some of these classes have corresponding iterators. An iterator is a class for safely traversing the items in a collection:

The refrence based collection classes work with pointers to items while the value based one store copies instead of pointers.

Architecture

There are three internal base classes for the reference based containers; QGCache, QGDict and QGList that operate on void* pointers. A thin template layer implements the actual collections by casting item pointers to and from void*.

This strategy allows Qt's templates to be very economical on space (instantiating one of these templates adds only inline-able calls to the base classes), while it does not hurt performance too much. The Qt Template Library in contrast is more like the STL. It does not store pointers, instead it stores real copies. This is faster for small values like integers or QRect for example. But the value based containers can not be used with everything derived from QObject since it is impossible to make a copy of a QObject

A QList Example

This example shows how to store Employee items in a list and prints them out in the reverse order:

    #include <qlist.h>
    #include <qstring.h>
    #include <stdio.h>

    class Employee
    {
    public:
        Employee( const char *name, int salary ) { n=name; s=salary; }
        const char *name()   const               { return n; }
        int         salary() const               { return s; }
    private:
        QString     n;
        int         s;
    };

    void main()
    {
        QList<Employee> list;           // list of pointers to Employee
        list.setAutoDelete( TRUE );     // delete items when they are removed

        list.append( new Employee("Bill", 50000) );
        list.append( new Employee("Steve",80000) );
        list.append( new Employee("Ron",  60000) );

        QListIterator<Employee> it(list); // iterator for employee list
        for ( it.toLast(); it.current(); --it) ) {
            Employee *emp = it.current();
            printf( "%s earns %d\n", emp->name(), emp->salary() );
        }
    }

Program output:

        Ron earns 60000
        Steve earns 80000
        Bill earns 50000

A QValueList Example

This example shows something compareable to the above QList example. It especially shows the value based semantics.

    #include <qvaluelist.h>
    #include <qstring.h>
    #include <stdio.h>

    class Employee
    {
    public:
        Employee( const QString& name, int salary ) { n=name; s=salary; }
        Employee( const Employee& _e ) { n = _e.name; s = _e.s; }

        QString     name()   const               { return n; }
        int         salary() const               { return s; }
        void        setSalary( int _s ) const    { s = _s; }
    private:
        QString     n;
        int         s;
    };

    void main()
    {
        typedef QValueList<Employee> EmployeeList;
        EmployeeList list;              // list of Employee

        list.append( Employee("Bill", 50000) );
        list.append( Employee("Steve",80000) );
        list.append( Employee("Ron",  60000) );

        Employee joe( "Joe", 50000 );
        list.append( joe );
        joe.setSalary( 4000 );

        EmployeeList::Iterator it;
        for( it = list.begin(); it != list.end(); ++it )
            printf( "%s earns %d\n", (*it).name(), (*it).salary() );
    }

Program output:

        Bill earns 50000
        Steve earns 80000
        Ron earns 60000
        Joe earns 50000

As you can see, the latest changes to Joes salary did not affect the value in the list because the list created a copy of Joes entry.

For more informations about value based containers see The Qt Template Library.

Managing Collection Items

All reference based collections inherit the QCollection base class. This class knows only the number of items in the collection and the delete strategy.

Items in a collection are by default not deleted when they are removed from the collection. The QCollection::setAutoDelete() function specifies the delete strategy. In the list example, we enable auto-deletion to make the list delete the items when they are removed from the list.

When inserting an item into a collection, only the pointer is copied, not the item itself. This is called a shallow copy. It is possible to make the collection copy all of the item's data (known as a deep copy) when an item is inserted. All collection functions that insert an item call the virtual function QCollection::newItem() for the item to be inserted. Inherit a collection and reimplement it if you want to have deep copies in your collection.

When removing an item from a list, the virtual function QCollection::deleteItem() is called. The default implementation in all collection classes is to delete the item if auto-deletion is enabled.

Usage

A reference based collection class, for instance QList<type>, defines a collection of pointers to type objects. The pointer (*) is implicit.

We discuss QList here, but the same applies for all reference based collection classes and all collection class iterators.

Template instantiation:

  QList<Employee> list;         // wherever the list is used

The item's class or type, Employee in our example, must be defined prior to the list definition.

  // Does not work: Employee is not defined
  class Employee;
  QList<Employee> list;

  // This works: Employee is defined before it is used
  class Employee {
    ...
  };
  QList<Employee> list;

Iterators

Although QList has member functions to traverse the list, it can often be better to make use of an iterator. QListIterator is very safe and can traverse lists that are being modified at the same time. Multiple iterators can work independently on the same collection.

A QList has an internal list of all iterators that are currently operating on the list. When a list entry is removed, the list updates all iterators to point to this entry.

The QDict and QCache collections have no traversal functions. To traverse these collections, you must use QDictIterator or QCacheIterator.

The value based containers do not have internal iterators. The reason is that these iterators are only 32 or 64 bit large depending in your CPU architecture. This means that the CPU can hold such an iterator in one of its registers and that in turn makes these iterators very quick.

Predefined Collections

Qt has the following predefined collection classes:

In almost all cases you should use QStringList. It is a value based container which as QString instances as elements. That implies that QStringList can deal with unicode very efficient. QStrList and QStrIList only store pointers to usual strings. That means that they can not store unicode data directly.

Comparison with the STL

We often get questions about why Qt does not use the STL, and why Qt's container templates are provided at all. Here are the major factors why we use and provide these templates: