迭代器

Prefer const iterators and cache end()

Prefer to use const_iterators over normal iterators when possible. Containers, which are being implicitly shared often detach when a call to a non-const begin() or end() methods is made (QList is an example of such a container). When using a const_iterator also watch out that you are really calling the const version of begin() and end(). Unless your container is actually const itself this probably will not be the case, possibly causing an unnecessary detach of your container. So basically whenever you use const_iterator initialize them using constBegin()/constEnd() instead, to be on the safe side.

Cache the return of the end() (or constEnd()) method call before doing iteration over large containers. For example:

This avoids the unnecessary creation of the temporary end() (or constEnd()) return object on each loop iteration, largely speeding it up.

When using iterators, always use pre-increment and pre-decrement operators (i.e., ++itr) unless you have a specific reason not to. The use of post-increment and post-decrement operators (i.e., itr++) cause the creation of a temporary object.

Take care when erasing elements inside a loop

When you want to erase some elements from the list, you maybe would use code similar to this:

This code will potentially crash because it is a dangling iterator after the call to erase().
You have to rewrite the code this way:
<syntaxhighlight lang="cpp-qt">
QMap<int, Job *>::iterator it = m_activeTimers.begin();
while (it != m_activeTimers.end()) {

dynamic_cast

You can only dynamic_cast to type T from type T2 provided
that:

T is defined in a library you link to (you'd get a linker error if this isn't the case, since it won't find the vtable or RTTI info)

T is "well-anchored" in that library. By "well-anchored" I mean that the vtable is not a COMMON symbol subject to merging at run-time by the dynamic linker. In other words, the first virtual member in the class definition must exist and not be inlined: it must be in a .cpp file.

T and T2 are exported

For instance, we've seen some hard-to-track problems in non-KDE C++ code we're linking with (I think NMM) because of that. It happened that:

libphonon loads the NMM plugin

NMM plugin links to NMM

NMM loads its own plugins

NMM's own plugins link to NMM

Some classes in the NMM library did not have well-anchored vtables, so dynamic_casting failed inside the Phonon NMM plugin for objects created in the NMM's own plugins.

Notice that window is created before the a.exec() call that starts the event loop. This implies that we want to avoid doing anything non-trivial in the top-level constructor, since it runs before we can even show the window.

The solution is simple: we need to delay the construction of anything besides the GUI until after the event loop has started. Here is how the example class MainWindow's constructor could look to achieve this:

<syntaxhighlight lang="cpp-qt">
MainWindow::MainWindow()
{

initGUI();
QTimer::singleShot( 0, this, SLOT(initObject()) );

}

void MainWindow::initGUI()
{

/* Construct your widgets here. Note that the widgets you
* construct here shouldn't require complex initialization
* either, or you've defeated the purpose.
* All you want to do is create your GUI objects and
* QObject::connect
* the appropriate signals to their slots.
*/

}

void MainWindow::initObject()
{

/* This slot will be called as soon as the event loop starts.
* Put everything else that needs to be done, including
* restoring values, reading files, session restoring, etc here.
* It will still take time, but at least your window will be
* on the screen, making your app look active.
*/

}

Using this technique may not buy you any overall time, but it makes your app seem quicker to the user who is starting it. This increased perceived responsiveness is reassuring for the user as they get quick feedback that the action of launching the app has succeeded.

When (and only when) the start up can not be made reasonably fast enough, consider using a KSplashScreen.

資料結構

在本節中，我們會繼續一些最常見的 pet-peeves，在 Qt/KDE 應用程式中影響資料結構非常常見。

Passing non-POD types

Non-POD ("plain old data") types should be passed by const reference if at all possible. This includes anything other than the basic types such as char and int.

Take, for instance, QString. They should always be passed into methods as const QString&. Even though QString is implicitly shared it is still more efficient (and safer) to pass const references as opposed to objects by value.

While there is a distinction between "null" QStrings and empty ones, this is a purely historical artifact and new code is discouraged from making use of it.

QString 和讀取檔案

If you are reading in a file, it is faster to convert it from the local encoding to Unicode (QString) in one go, rather than line by line. This means that methods like QIODevice::readAll() are often a good solution, followed by a single QString instantiation.

For larger files, consider reading a block of lines and then performing the conversion. That way you get the opportunity to update your GUI. This can be accomplished by reentering the event loop normally, along with using a timer to read in the blocks in the background, or by creating a local event loop.

While one can also use qApp->processEvents(), it is discouraged as it easily leads to subtle yet often fatal problems.

Reading QString from a KProcess

KProcess emits the signals readyReadStandard{Output|Error} as data comes in.
A common mistake is reading all available data in the connected slot and converting it to QString right away: the data comes in arbitrarily segmented chunks, so multi-byte characters might be cut into pieces and thus invalidated. Several approaches to this problem exist:

Do you really need to process the data as it comes in? If not, just use readAllStandard{Output|Error} after the process has exited. Unlike in KDE3, KProcess is now able to accumulate the data for you.

Wrap the process into a QTextStream and read line-wise. This should work starting with Qt 4.4.

Accumulate data chunks in the slots and process them each time a newline arrives or after some timeout passes. Example code

QString 和 QByteArray

While QString is the tool of choice for many string handling situations, there is one where it is particularly inefficient. If you are pushing about and working on data in QByteArrays, take care not to pass it through methods which take QString parameters; then make QByteArrays from them again.

The expensive thing happening here is the conversion to QString, which does a conversion to Unicode internally. This is unnecessary because, the first thing the method does is convert it back using toLatin1(). So if you are sure that the Unicode conversion is not needed, try to avoid inadvertently using QString along the way.