Skip to content

KDAB contributions to Qt 5.0 (part 4)

Continuing the series on KDAB contributions to Qt 5.0 (part 1, part 2, part 3), this time we cover C++11, and various optimizations.

C++11 support

There have been many people and companies working on C++11 support in Qt 5. KDAB was involved in several Qt 5 features which relate to C++11. An overview of the features in Qt 5 which relate to C++11 is available from a presentation last Autumn.

One of the porting issues in a Qt 4 to 5 transition is that the QSKIP macro now takes only one argument where previously it took two. This is a source incompatibility for users to deal with. As macros can not be overloaded the way that functions can, a different solution is needed. That’s where  variadic macros become useful. If C++11 is enabled when compiling a file which uses QSKIP, the definition of that macro looks like this:

#define QSKIP(statement, ...) QSKIP_INTERNAL(statement)

The QSKIP_INTERNAL macro is the implementation of the regular QSKIP, so the C++11 version accepts any number of arguments, but silently drops all arguments except the first one.

Almost a year ago, I added a Q_DECL_OVERRIDE define corresponding to the C++11 override keyword. I also added a define for marking methods as ‘deleted’ and used it to ‘delete’ some methods which have previously only been private, and some constructors which should no longer be used in Qt 5. This makes for slightly better compiler error messages when attempting to use those methods.

With the Q_DECL_FINAL, corresponding to the C++11 final keyword, already defined in Qt 5, moc, some other internal tools and other features in Qt 5 needed to be adapted to handle it. The ‘final’ concept in Qt is somewhat complex, because aside from supporting the C++11 final keyword, the MSVC non-standard extension for ‘sealed’ classes is used in C++98 mode.

Similarly, the pre-existing Q_DECL_NOEXCEPT define gained a sibling in the Q_DECL_NOTHROW define. Although exceptions are not a central part of the Qt API and error handling model of Qt itself, it is also important to ensure that downstreams using exceptions more extensively can do so while taking advantage of C++11 features. This too enables an MSVC extension which is similar enough to the C++11 noexcept feature to be related to it. The Q_DECL_NOTHROW is defined as Q_DECL_NOEXCEPT where possible.

Something which has no C++98 equivalent is the constexpr keyword. This allows compile-time computation of certain constants. By marking the API of the Qt geometric classes as constexpr, many expressive possibilities, including calculation, open up to the programmer which were not possible before:

constexpr QPoint twelve_twelve(12, 12);

  switch(someInt)
  {
    case QPoint(15, 15).x():
      break;
    case twelve_twelve.x():
      break;
//  case QPoint(12, 12).x(): // ### Error: Duplicate of above.
//    break;
    case (twelve_twelve + QPoint(4, 4)).x():
      break;
// No magic number for the value being tested anymore:
    case QRect(twelve_twelve, QSize(40, 20).transposed()).bottomRight().x():
      break;
    case QLine(QPoint(4, 5), QPoint(6, 7)).translated(twelve_twelve).x2():
      break;
  }

We also added the constexpr marker to a few other locations in Qt 5, such as in QModelIndex, and some in QFlags. The full possibilities and patterns of this are still to be discovered.

Optimization in signal slot connections

With the rewrite of how signals ans slots work in Qt 5, there were suddenly mutliple implementations of what could happen when a connection is made. The natural way for C++ developers to create an abstraction for that is polymorphism and virtual methods. This works well usually, but when virtual functions are used in a class causes the compiler to have to create extra functions and data which it would not otherwise have to. In small doses, that is not a problem, but as the new connection syntax creates a lot of these objects, their unwanted price adds up. An optimization inspired by a boost feature in a similar problem domain was added by KDAB.

A follow-up patch re-enabled tail call optimization, to allow the compiler to make further optimizations in all cases.

qEnvironmentVariableIsSet and qEnvironmentVariableIsEmpty

Qt 5 sports a new way of testing for the existence of environment variables. These are a more modern (allowing the use of C++11 noexcept) and exception-safe version of the pre-existing methods for querying the environment.

QStringList::join(QChar)

Also in the domain of optimizations, a new overload of QStringList::join was added by KDAB in Qt 5. This avoids conversion of the QChar into a QString only to iterate over the QChars inside it again. Everyone gets the performance improvement for free when joining strings with a single character.

Removing use of QtAlgorithms

Several algorithms available in Qt are conceptual duplicates of what is provided in standard algorithms, such as qFind and std::find. The reasons for those algorithms to exist is partly because built-in platform support for them was not previously good enough. For Qt 5, the target platforms are modern enough that we can assume a working STL for our purposes. Unfortunately, due to some implemenation and behavioral differences, it was not possible to remove the QtAlgorithms, or to implement them in terms of the standard algorithms and gain the benefits that brings automatically.

Slowly though, we can port the implementation of Qt to use standard algorithms instead of the Qt ones. KDAB is participating in creating some patches towards this effort as it grows.

2 thoughts on “KDAB contributions to Qt 5.0 (part 4)”

  1. > Unfortunately, due to some implemenation and behavioral differences

    Do you mean implementation and behavioral differences between the Qt Algorithms functions and the STL equivalents or between different implementations of the same STL functions (eg. between Visual Studio and libstdc++)? If you mean the latter, do you have any examples?

Leave a Reply

Your email address will not be published. Required fields are marked *