Hands-On High Performance Programming with Qt 5
上QQ阅读APP看书,第一时间看更新

QList

This container is used very often in the Qt API and, before the advent of Qt 5, was taught to Qt programmers to be the default Qt container. However, today it has fallen into disrepute and its usage is discouraged because it can be problematic for performance.

First and foremost, QtList isn't anything like std::list. Internally, it holds an array of void* pointers. And now the complications begin. There are two modes for using those pointers—the first one is when they are just pointing to object instances; the second one is when they are reused as direct storage for small objects. The small objects optimization will be triggered when the object size is smaller or equal to the size of void* and if Q_MOVABLE_TYPE was specified for this object's type.

There is a second optimization which somehow warrants usage if list is in the class name. QList leaves a free place at the start of its internal data buffer, thus accelerating front insertions and deletions as well as middle-of-the-list insertions.

The third optimization was the attempt to reduce the amount of code generated for templated containers because QList uses common, type-independent code for the management of the void* array. That was indeed important in former days when compilers and linkers still couldn't really cope with the template bloat but the issue is not that acute today.

So, what do we think about this class and why is usage of QList discouraged? The problem with it is that the small object optimization doesn't work for all small Qt classes, because not all of them are tagged as relocatable. This was probably an oversight, but because of the abstract binary interface (ABI) compatibility, it probably won't be fixed. So, if a class isn't suitably tagged, QList will internally use an array of pointers to objects with all the performance penalties of the linked list—allocator calls and pointer chasing. Some often-used Qt classes will trigger small object optimization though, for example QString, QByteArray, QFileInfo, QIcon, QBrush, and QPen among others, but many others do not.

So, what is the conclusion? If you fully understand the performance implications, use it, otherwise the safer alternative is to use QVector or std::vector.