Gpg4win v2.0.4 released

Gpg4win LogoFrom the announcement:

We are pleased to announce the availability of a new stable Gpg4win release: Version 2.0.4.

The download is available via the usual download page:

http://www.gpg4win.org/download.html

This release contains a security fix for GPGSM.

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.

BC/SC Gotcha: reimplementing a virtual function


This might surprise you: Adding a reimplementation of a base class virtual function to a derived class might be binary incompatible. Here’s why.

Assume you have the following classes in a library that maintains binary compatibility across releases:

// release 1.0
struct base { virtual f() {} };
struct derived : base {}; // doesn't reimplement base::f()

And in an application using the above library:

derived d;
d.f(); // ok, calls base::f()

Q: Is d.f() a virtual function call?
A: No. Not if your compiler is any good.

When the compiler can prove the dynamic type of an object, it will resolve the polymorphic calls at compile time. In other words: It will de-virtualise the call.

In our case, the compiler can prove that d‘s dynamic type is derived, so it just inserts the function call to base::f(). Don’t believe me? Ask your compiler:

struct base {
    virtual ~base();
    virtual void f() const;
};

struct derived : base {
    //void f() const;
};

void foo1( derived d ) {
    d.f();
}

void foo2( const derived & d ) {
    d.f();
}

My GCC gives me (with -O) these assembly listings for foo1() and foo2(), resp.:

foo1() foo2()

_Z4foo17derived:
.LFB2:
subq $8, %rsp
.LCFI1:
call _ZNK4base1fEv
addq $8, %rsp
ret

_Z4foo2RK7derived:
.LFB3:
subq $8, %rsp
.LCFI0:
movq (%rdi), %rax
call *16(%rax)
addq $8, %rsp
ret

Even if you don’t speak AMD64 assembler, you will recognise that foo1() calls base::f() directly while foo2() calls indirectly through base‘s virtual function table.

Now, assume we’re adding a reimplementation of base::f() to derived:

// release 1.1
struct derived : base {
    /* reimp */ void f() {}
};

But we won’t recompile the application. What happens is that the application still calls base::f(). Yes, even across DSOs. The linker will replace the direct function call with an indirect one into the DSO, for sure. But it won’t second-guess the compiler and insert a virtual function table lookup again.

So now that the mechanism is clear (hopefully): Is this a binary compatibility issue?

That depends entirely on what the new functions do. If they (even ever-so-slightly) reinterpret the meaning of data in the class, class invariants might be in jeopardy.

Consider this: Code in the application that can prove the dynamic type of a base instance is a derived will not call the new reimplementations. Code that cannot, will. An instance that will be manipulated with one set of functions on one hand, and another on the other might have a hard time maintaining its class invariants if one set of functions expects one set of invariants, and the other another.

Note how this is similar to changing functions with inline linkage: Depending on whether the compiler decides to inline the code at one particular call site or not, the old copy or the new copy of the code will be called. The difference is one of awareness: If you change a method with inline linkage, you are usually aware of the possible problem. When adding a reimplementation of a virtual function, you’re probably not. Up to now you weren’t, that is :).

To summarise: Adding a reimplementation of a virtual function to a class can lead to clients of the class either calling or not calling the new implementation, depending on whether the compiler can prove at compile time that static and dynamic type of an instance are the same. For the same instance, this will typically succeed in one function and fail in another. Problems arise when the reimplementation does not take into account that it might be bypassed.

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.

Protected: What’s in a Proxy Style?

This content is password protected. To view it please enter your password below:

Heise iX: iX Spezial “Programmieren Heute” available as eBook

I just noticed that the iX Spezial “Programmieren Heute”, to which yours truly contributed a state-of-the-union article on C/C++, is “now” (well, since April) available as eBook. Needless to say (the title indicates it already), the whole thing is in German.

From the article:

Auch wenn C++ nicht gerade als beliebt unter Entwicklern gelten darf, wird die Sprache sie noch eine Weile begleiten – vor allem, weil der Bedarf an hardwarenahen Sprachen wie C++ oder seiner Alternative D sich in nächster Zeit erhöhen dürfte.

I’m still not through all the other articles in my tr(Belegexemplar)—it’s that interesting 🙂

Go get it at Dpunkt.de.

Disclaimer: I don’t get any proceeds from this, only the author’s fee, which was fixed.

Heise Developer: Dem Elfenbeinturm entreißen

A little belatedly, I guess, but here we go:

For you German speakers out there, my first Heise Developer article, “Dem Elfenbeinturm entreißen: Über den praxisrelevanten Einsatz der Template-Metaprogrammierung“, “just” went live on Heise’s site.

It shows how to use TMP to convert from QVariant to boost::variant<>. Even if you don’t speak German, you might be interested in the sample source code: ftp://ftp.heise.de/pub/ix/developer/elfenbein.zip.

From the article:

Als Ansatz für eine Konvertierungsfunktion lässt sich Folgendes schreiben.

template <typename T_Variant>
T_Variant qvariant2variant( const QVariant & qv ) {
  for( T : types(T_Variant) )
    if ( qv.type() == T )
      return T_Variant( qvariant_cast<T>( qv ) );
  throw bad_cast( "..." );
};

Es fehlen noch zwei Dinge, um aus dem Pseudocode “richtigen” Code zu erstellen: Erstens ein Weg, um einen Typ T auf den dazugehörigen QVariant-internen Diskriminator abzubilden. Das leistet das Funktions-Template qMetaTypeId() […].

Zweitens ein Weg, um “für jeden Typ T, den T_Variant enthalten kann”, abzubilden. Das lässt sich mit TMP lösen (Stichwort: Liste von Typen), was die Aufgabe für den Rest des Artikels sein wird.