Effective Qt @ Meeting C++ 2015: talk is now online

Effective Qt continues as a conference-driven series!

After the guys at Qt World Summit last year managed to mess up the recording of exactly one of the many, many talks there (my Effective Qt one, of course), this is to let you know that Jens Weller of Meeting C++ has uploaded the recording of my Effective Qt talk to his conference channel on YouTube.

I talk about Q_FOREACH vs. C++11 range-for, QLatin1String vs. QStringLiteral, as well as, of course, how bad QList is.



Understand the Qt Containers: The Data

This is just a short heads-up to those that have asked for quantitative measurements. I’ve begun updating “Understand the Qt Containers” with a section on data.

As of now, the memory and append performance is in. I’ll re-run the iteration test over the night once more (I’ve detected an anomaly that I’d like the verify first), and re-add them again, when done.

Effective Qt: Understand the Qt Containers

The third of my Effective Qt columns, “Understand the Qt Containers“, just went live on my site.

If you know me, you will know what awaits you there 🙂 I hope I have not disappointed you. That said, this is just a first part. I plan to eventually extend it to cover more containers (currently, just QVector and QList), and give more data and assembler code for the containers I’ve already described.

These are the guidelines this item covers:

  • Remember that QList has nothing to do with std::list, and QSet has nothing to do with std::set.
  • Be aware of the two Qt container APIs, Qt-ish and STL-compatible, and avoid mixing their use in the same project.
  • Familiarise yourself with the STL containers and the additional features they offer.
  • Prefer member-swap over assignment wherever possible to express move semantics. Use C++11 rvalue move semantics if the class and the compiler support them.
  • [[EDIT 2011-08-25: new]] Always use constBegin()/constEnd() (cbegin()/cend()) when assigning the result to a const_iterator.
  • Avoid modifying a container (remove/insert elements) while iterating. If you have to, use an STL algorithm, such as one of the std::remove() family.
  • Prefer the STL-compatible iterators over the Java-style ones.
  • If you do use the Java-style iterators, avoid using the mutating ones.
  • Prefer to use const references as the first argument of Q_FOREACH, unless the element type is customarily passed by value.
  • Familiarise yourself with BOOST_FOREACH, and the additional features it offers.
  • Declare your enums and QFlags as Q_PRIMITIVE_TYPE if there’s a chance they will be held in Qt containers.
  • Declare your value-types Q_MOVABLE_TYPE if there’s a chance they will be held in Qt containers.
  • Don’t change the classification of a type if you need to maintain binary compatibility.
  • Prefer vector (std or Q) over QList.
  • Avoid QList<T> where T is not declared as either Q_MOVABLE_TYPE or Q_PRIMITIVE_TYPE or where sizeof(T) != sizeof(void*) (remember to check both 32 and 64-bit platforms).
  • [[EDIT 2011-08-16: new]] Avoid using vectors of types for which Qt APIs customarily use QList, and for which QList is not inefficient.

Hope you enjoy!

Effective Qt: Prefer to use normalised signal/slot signatures

The second of my Effective Qt columns, “Prefer to use normalised signal/slot signatures“, just went live on my site.

There is only one guideline this item covers:

  • Prefer normalised signal/slot signatures in connect statements.

Hope you enjoy!

Sneak Preview: QList considered harmful

[[EDIT 2011-08-15: This has since been extended into a full Effective Qt column.]]

We knew for a long time that QList is not a good default container, despite what the documentation claims. The problem boils down to the fact that for a lot of types T, QList<T> is needlessly inefficient by allocating elements on the heap and storing pointers to them instead of storing the elements in-place, like e.g. QVector does. Sometimes, for large and complex types, that might be exactly what you want, but a conservative estimate would put that chance at less than 5%.

It never ceases to amaze me how people trained in the STL default to std::vector until a profiler tells them that they should use a std::list or std::deque instead, whereas people trained in Qt default to QList and not QVector.

Effective Qt will soon come out with all the gory details, but since KDE’s 4.5 and Qt’s 4.7 releases are imminent, I decided to give you a sneak preview of just how widespread this inefficiency is. In order to do that, I finally sat down and developed a patch that emits a warning when you try to add something to an inefficient QList (at least if you set your compiler to warn for signed/unsigned integer comparison warnings). It’s been developed and tested with GCC 4.3 and Qt 4.6.3, but should work for a lot of other compilers, too. Please send me warning generators for your compiler in comments.

The patch is binary-compatible, so you don’t have to recompile your Qt after applying it.

Here’s a (incomplete) list of inefficient uses of QList (in the following, T and S are arbitrary type):

  • QVariant (!!) is too large.
  • QVector<T> isn’t marked as movable, even though it is.
  • QSharedPointer<T> is too large.
  • Virtually any QPair<T,S> is too large.
  • Enums not marked as movable.

Run, don’t walk, and fix your new API to not use QList, or mark your new types as movable (details are in the patch). Alas, both changes are binary incompatible, so you can’t do them if you need your code to stay BC. This might be one of the reasons why QPair and QVector aren’t “fixed” yet: doing so would change the layout of the QList instantiated with them :(.

But, at least for new code, there’s no excuse anymore: Just apply the patch.

Effective Qt: Don’t be sub-class when subclassing

The first of my Effective Qt columns, “Don’t be sub-class when subclassing“, just went live on my site.

Here are the guidelines this item covers:

  • When subclassing QObject (directly or indirectly), always add the Q_OBJECT macro, regardless of whether you also define signals or slots.
  • Prefer to offer all base class constructors in subclasses, too.
  • Prefer to offer the basic QObject constructor ( QObject * parent=0 ) when subclassing QObjects. Always offer the basic QWidget constructor ( QWidget * parent=0, Qt::WindowFlags f=0 ) when subclassing QWidget.
  • Prefer to follow the Qt constructor pattern: When inheriting QObjects, end constructor argument lists in QObject * parent=0. When inheriting QWidgets, end constructor argument lists in QWidget * parent=0, Qt::WindowFlags f=0. Add additional arguments at the beginning of the argument list.

I hope to make this into a regular column, time permitting.