[C++/Qt] Concaténation de chaînes de caractères

Posté le Wednesday, 22 December 2010 in Programmation

Présentation

Qt est un framework orienté objet écrit en C++ et permettant de faire des interfaces graphiques à l’aide de ces widgets. Ce framework est utilisé par le projet KDE depuis ses débuts pour en faire un environnement très complet.

Qt permet donc de faire des interfaces graphiques mais aussi d’accéder à des bases de données SQL, de faire de la communication réseau, une gestion simplifiée des threads, la lecture de fichier XML. Qt intègre aussi le moteur HTML Webkit.

Qt ajoute une couche supplémentaire au C++ permettant de faire de l’introspection de classe un peu plus poussée (comme l’appel d’une méthode dont on ne connaît le nom qu’à l’exécution). Qt permet également la gestion d’évènement par l’intermédiaire d’un système puissant de SIGNALS et de SLOTS.

Dans la suite de cet article nous allons nous concentrer sur une très petite partie de Qt mais qui est utilisée dans beaucoup d’applications écrites en Qt : les chaînes de caractères, et plus précisément, la concaténation de chaînes de caractères.

Concaténation de chaînes de caractères.

Comme dans d’autres langages, la concaténation de chaînes de caractères se fait à l'aide de l'opérateur +. Prenons un exemple simple :

#include <QString>

QString abc = "abc", def = "def";
QString result;
result = abc + def;

L'utilisation de l'opérateur + facilite l'écriture de la concaténation des chaînes de caractères (tout comme l'opérateur == permet de facilement comparer des chaînes de caractères de type QString).

Malheureusement cette écriture rend le code peu performant pour diverses raisons (que l’on peut retrouver dans la documentation de l’objet QString).

Concaténation rapide de chaînes de caractères

A partir de Qt 4.6, Nokia, a ajouté un template nommé QStringBuilder (cet objet fait beaucoup penser à l'objet StringBuilder de JAVA permettant d'accélérer les concaténations de chaînes de caractères).

Ce template ne s’utilise pas directement mais au travers de l'opérateur %. En remplaçant donc l'opérateur + par % on gagne en performance (dixit la doc de Qt).

Pour pouvoir utiliser l'opérateur, il suffit d'inclure le fichier QStringBuilder :

#include <QStringBuilder>

QString abc = "abc", def = "def", ghi = "ghi";
QString result;
result = abc % def % ghi;

Une autre possibilité est de définir (par exemple dans votre fichier .pro ou dans un include général de votre application) les définitions QT_USE_FAST_CONCATENATION, et QT_USE_FAST_OPERATOR_PLUS.

Ces définitions permettent de remplacer l'opérateur + par l'opérateur % dans toute l'application. Par contre cette opération peut demander quelques modifications de votre code.

#define QT_USE_FAST_CONCATENATION
#define QT_USE_FAST_OPERATOR_PLUS
#include <QString>

QString abc = "abc", def = "def";
QString result;
result = abc + def;

Benchmark

Nous allons donc dans la suite du document vérifier que l'opérateur % est plus rapide que l'opérateur +. Pour cela nous allons utiliser le module de benchmark de Qt.

Code source

Voici le petit programme permettant de tester la performance de la concaténation. Notre exemple simple va constituer à la concaténation de 26 chaînes de caractères créées au début. L'appel se fera une première fois en utilisant l'opérateur + et une seconde fois en utilisant l'opérateur %.

#include <QtCore/QString>
#include <QtTest/QtTest>
#include <QStringBuilder>

class TestPerf : public QObject
{
    Q_OBJECT
public:    
    TestPerf();
private Q_SLOTS:    
    void concat();    
    void concat_data();
};

TestPerf::TestPerf()
{
}

void TestPerf::concat()
{    
    QFETCH(bool, useStringBuilder); 
    QString result;
    QString a("a"), b("b"), c("c"), d("d"), e("e"), f("f"), g("g"), 
    h("h"), i("i"), j("j"), k("k"), l("l"), m("m"), n("n"), o("o"), 
    p("p"), q("q"), r("r"), s("s"), t("t"), u("u"), v("v"), w("w"), 
    x("x"), y("y"), z("z");

    if (useStringBuilder)
    {       
        QBENCHMARK {           
            // Concaténation en utilisant QStringBuilder         
            // Dans ce cas la concaténation devrait être plus rapide         
            result = a % b % c % d % e % f % g % h % i % j % k % l % 
            m % n % o % p % q % r % s % t % u % v % w % x % y % z;        
        }   
    }   
    else 
    {       
        QBENCHMARK      
        {           
            // Concaténation en n'utilisant pas QStringBuilder. On 
            // utilise alors la concaténation normal de chaînes de 
            // caractères en utilisant QString           
            result = a + b + c + d + e + f + g + h + i + j + k + l + 
            m + n + o + p + q + r + s + t + u + v + w + x + y + z;        
        }   
    }
}

void TestPerf::concat_data()
{    
    QTest::addColumn<bool>("useStringBuilder"); 
    QTest::newRow("Don't use QStringBuilder") << false; 
    QTest::newRow("Use QStringBuilder") << true;
}

QTEST_APPLESS_MAIN(TestPerf);

#include "tst_testperf.moc"

Résultat du test

Le test a été fait en utilisant la version 4.6.3 de Qt. Le résultat est sensiblement le même avec la version 4.7.0

Sans QStringBuilder Avec QStringBuilder
0.00367 msec 0.00046 msec

On voit dans ce test que la version en utilisant QStringBuilder est 8 fois plus rapide que sans. Bien sûr vu le temps que prend la concaténation de chaînes de caractères, ce test commence à avoir de l'intérêt uniquement à partir du moment où on fait beaucoup de concaténation dans la seconde, ou si les temps de réponses sont critiques.

Sur ce, je vous souhaite à tous un Joyeux noël et une bonne année.

Le programme

Vous pouvez trouver le programme ici.