Sur cette page

Changements apportés à Qt Core

Qt 6 est le résultat d'un effort conscient pour rendre le cadre plus efficace et plus facile à utiliser.

Nous essayons de maintenir la compatibilité binaire et source pour toutes les API publiques dans chaque version. Mais certains changements étaient inévitables dans un effort pour faire de Qt un meilleur framework.

Dans cette rubrique, nous résumons ces changements dans Qt Core, et fournissons des conseils pour les gérer.

Classes de conteneurs

QHash, QMultiHash, QSet

Signature de qHash()

Pour les types personnalisés, QHash et QMultiHash dépendent de la fourniture d'un custom qHash() function dans le même espace de noms. Dans Qt 4 et Qt 5, la valeur de retour et le deuxième argument facultatif d'une fonction qHash étaient de type uint. Dans Qt 6, il s'agit de size_t.

En d'autres termes, vous devez remplacer

uint qHash(MyType x, uint seed);

à

size_t qHash(MyType x, size_t seed);

Cela permet à QHash, QMultiHash et QSet de contenir plus de 2^32 éléments sur les plates-formes 64 bits.

Stabilité des références

L'implémentation de QHash, QMultiHash et QSet dans Qt 6 est passée d'une approche basée sur les nœuds à une table de recherche en deux étapes. Cette conception permet de maintenir la surcharge mémoire d'une instance de hachage très faible, tout en offrant de bonnes performances.

Un changement de comportement à noter est que la nouvelle implémentation ne fournira pas de références stables aux éléments du hachage lorsque la table doit croître, ou lorsque des entrées sont supprimées. Les applications qui s'appuient sur une telle stabilité peuvent maintenant avoir un comportement indéfini.

Suppression de QHash::insertMulti

Dans Qt 5, QHash pouvait être utilisé pour créer des hachages à valeurs multiples en utilisant QHash::insertMulti, et QMultiHash dérivait de QHash.

Dans Qt 6, les deux types et cas d'utilisation sont distincts, et QHash::insertMulti a été supprimé.

QVector, QList

Avant Qt 6, QVector et QList étaient des classes distinctes. Dans Qt 6, elles sont unifiées : L'implémentation de Qt 5 QList a disparu et les deux classes utilisent à la place l'implémentation mise à jour de QVector. QList est la classe avec l'implémentation actuelle et QVector est un alias (typedef) de QList.

QListLes fonctions fromVector() et toVector() de Qt 5, et les fonctions fromList() et toList() de QVector n'impliquent plus de copie de données dans Qt 6. Elles renvoient maintenant l'objet pour lequel elles ont été appelées.

Changements dans l'API

QListLe type de taille de QVector(et donc de ) passe de int à qsizetype. En même temps que le type de taille, les signatures de toutes les méthodes concernées sont mises à jour pour utiliser qsizetype. Cela permet à QList de contenir plus de 2^31 éléments sur les plateformes 64 bits.

Lors de la mise à jour de la base de code vers Qt 6, ce changement d'API entraînerait très probablement des avertissements du compilateur concernant les conversions de type étroites. Si vous avez l'exemple de code suivant, vous devrez le mettre à jour pour utiliser les conversions de type étroites :

void myFunction(QList<MyType> &data) {
    int size = data.size();
    // ...
    const int pos = getInsertPosition(size);
    data.insert(pos, MyType());
    // ...
}

vous devrez le mettre à jour pour utiliser qsizetype ou un mot-clé auto :

void myFunction(QList<MyType> &data) {
    auto size = data.size();
    // ...
    const auto pos = getInsertPosition(size);
    data.insert(pos, MyType());
    // ...
}

Sinon, vous pouvez utiliser la conversion de type et tout convertir en int ou en qsizetype.

Note : Si vous voulez construire avec Qt 5 et Qt 6, le mot-clé auto est une bonne solution pour couvrir les différences de signature entre les versions.

Disposition de la mémoire

QList Qt 6 a reçu de nombreux changements liés à la disposition de la mémoire.

Dans Qt 5, sizeof(QList<T>) était égal à la taille d'un pointeur. Désormais, l'indirection supplémentaire du pointeur est supprimée et les membres de données de QList sont directement stockés dans l'objet. Par défaut, sizeof(QList<T>) devrait être égal à la taille de 3 pointeurs.

En même temps, la disposition de la mémoire des éléments est également mise à jour. QList stocke désormais toujours ses éléments directement dans la région de mémoire allouée, contrairement à Qt 5, où certains objets étaient alloués séparément sur le tas et où les pointeurs vers les objets étaient placés dans QList à la place.

Notez que ce dernier point affecte en particulier les objets de grande taille. Pour obtenir le comportement de Qt 5, vous pourriez envelopper vos objets dans des pointeurs intelligents et stocker ces pointeurs intelligents dans QList directement. Dans ce cas, le type de votre QList serait QList<MySmartPointer<MyLargeObject>> au lieu de QList<MyLargeObject> dans Qt 5.

Stabilité des références

Plusieurs changements ont été apportés à l'implémentation de QVector/QList. Le changement lié à QVector est l'optimisation de l'insertion au début (de la même manière que pour QList dans Qt 5). La modification liée à QList est la suivante : la disposition de la mémoire pour les éléments est simplifiée.

Important : ces changements ont un impact sur la stabilité des références. Dans Qt 6, vous devez considérer que toute méthode modifiant la taille ou la capacité invalide toutes les références, même lorsque QList n'est pas implicitement partagé. Les exceptions à cette règle sont documentées explicitement.

Les applications qui s'appuient sur une certaine stabilité des références peuvent avoir un comportement indéfini lorsqu'elles sont mises à jour pour utiliser Qt 6. Vous devez prêter une attention particulière aux cas où QVector ou QList avec une disposition de tableau non compatible avec le langage C ont été utilisés à l'origine.

Voir les classes dans Qt6

Aperçu général

Plusieurs nouvelles classes View arrivent avec Qt6. Il y a la classe déjà existante QStringView, maintenant accompagnée de QByteArrayView et suivie d'une classe spécialisée QUtf8StringView et d'une classe plus universelle QAnyStringView.

Introduction aux classes de vues sur l'exemple de QStringView

La classe QStringView fournit une vue unifiée des chaînes UTF-16 avec un sous-ensemble en lecture seule de l'API QString. Contrairement à QString, qui conserve sa propre copie de la chaîne (éventuellement recomptée), QStringView fournit une vue d'une chaîne stockée ailleurs.

char hello[]{ "Hello." };   // narrow multi-byte string literal
QString str{hello};         // needs to make a copy of the string literal
QString strToStr(str);      // atomic increment involved to not create a copy of hello again

// The above code can be re-written to avoid copying and atomic increment.

QStringView view{ u"Hello." };  // view to UTF-16 encoded string literal
QStringView viewToView{ view }; // view of the same UTF-16 encoded string literal

La chaîne "Hello." est stockée dans le fichier binaire et n'est pas allouée au moment de l'exécution. view n'est qu'une vue de la chaîne "Hello.", et aucune copie ne doit donc être créée. Lorsque nous copions un QStringView, le viewToView observe la même chaîne que celle observée par le view copié. Cela signifie que viewToView n'a pas besoin de créer une copie ou un incrément atomique. Il s'agit de vues sur la chaîne existante "Hello.".

Vues en tant qu'argument de fonction

Les vues doivent être transmises par leur valeur, et non par une référence à une constante.

void myfun1(QStringView sv);        // preferred
void myfun2(const QStringView &sv); // compiles and works, but slower

Fonctions de manipulation des vues

QStringView prend en charge les fonctions qui nous permettent de manipuler la vue de la chaîne de caractères. Cela nous permet de modifier la vue sans créer une copie partielle de la chaîne vue.

QString pineapple = "Pineapple";
QString pine = pineapple.left(4);

// The above code can be re-written to avoid creating a partial copy.

QStringView pineappleView{ pineapple };
QStringView pineView = pineappleView.left(4);

Chaînes non terminées par des zéros et chaînes contenant des zéros '\0'

QStringView supporte à la fois les chaînes à terminaison nulle et les chaînes à terminaison non nulle. La différence vient de la façon dont vous initialisez la chaîne QStringView:

QChar aToE[]{ 'a', 'b', 'c', 'd', 'e' };

QStringView nonNull{ aToE, std::size(aToE) }; // with length given
QStringView nonNull{ aToE }; // automatically determines the length

QChar fToJ[]{ 'f', 'g', 'h', '\0', 'j' };

// uses given length, doesn't search for '\0', so '\0' at position 3
// is considered to be a part of the string similarly to 'h' and 'j
QStringView nonNull{ fToJ, std::size(fToJ) };
QStringView part{ fToJ }; //stops on the first encounter of '\0'

Modèle de propriété des vues

Comme views n'est pas propriétaire de la mémoire qu'il référence, il faut veiller à ce que les données référencées (par exemple, appartenant à QString) survivent à view sur tous les chemins de code.

QStringView sayHello()
{
    QString hello("Hello.");
    return QStringView{ hello }; // hello gets out of scope and destroyed
}

void main()
{
    QStringView hello{ sayHello() };
    qDebug() << hello; // undefined behavior
}

La conversion d'un QStringView en QString

QStringView ne sera pas implicitement ou explicitement convertie en QString, mais peut créer une copie profonde de ses données :

void print(const QString &s) { qDebug() << s; }

void main()
{
    QStringView string{ u"string"};

    // print(string); // invalid, no implicit conversion
    // QString str{ string }; // invalid, no explicit conversion

    print(string.toString());
    QString str = string.toString(); // create QString from view
}

Remarques importantes

En tirant parti des nouvelles classes de vues, il est possible d'améliorer considérablement les performances dans de nombreux cas d'utilisation. Cependant, il est important de savoir qu'il peut y avoir quelques mises en garde. Il est donc important de s'en souvenir :

  • Les vues doivent être transmises par valeur, et non par référence à une constante.
  • Construire une vue avec une longueur négative est un comportement non défini.
  • Il faut veiller à ce que les données référencées (par exemple, appartenant à QString) survivent à la vue dans tous les chemins de code.

La classe QStringView

À partir de Qt6, il est généralement recommandé d'utiliser QStringView plutôt que QStringRef. QStringView fait référence à une portion contiguë d'une chaîne UTF-16 qui ne lui appartient pas. Il s'agit d'un type d'interface pour toutes sortes de chaînes UTF-16, sans qu'il soit nécessaire de construire d'abord un QString. La classe QStringView expose presque toutes les méthodes en lecture seule de QString et de la classe QStringRef qui existait précédemment.

Remarque : il convient de veiller à ce que les données de la chaîne référencée (par exemple, appartenant à QString) survivent à QStringView sur tous les chemins de code.

Remarque : si un QStringView enveloppe un QString, il faut faire attention car, contrairement à QStringRef, QStringView ne mettra pas à jour le pointeur de données interne une fois que les données de QString auront été relocalisées.

QString string = ...;
QStringView view{string};

// Appending something very long might cause a relocation and will
// ultimately result in a garbled QStringView.
string += ...;

La classe QStringRef

Dans Qt6, QStringRef a été supprimé de Qt Core. Pour faciliter le portage des applications existantes sans toucher à l'ensemble de la base de code, la classe QStringRef n'a pas complètement disparu et a été déplacée dans le module Qt5Compat. Si vous souhaitez utiliser davantage QStringRef, consultez la section Utilisation du module Qt5Compat.

Malheureusement, certaines méthodes exposées par QString retournant un QStringRef, n'ont pas pu être déplacées dans Qt5Compat. Un portage manuel peut donc s'avérer nécessaire. Si votre code utilise une ou plusieurs des fonctions suivantes, vous devez les porter pour utiliser QStringView ou QStringTokenizer. Il est également recommandé d'utiliser QStringView::tokenize plutôt que QStringView::split pour les codes dont les performances sont critiques.

Modifier le code utilisant QStringRef:

QString string = ...;
QStringRef left = string.leftRef(n);
QStringRef mid = string.midRef(n);
QStringRef right = string.rightRef(n);

QString value = ...;
const QVector<QStringRef> refs = string.splitRef(' ');
if (refs.contains(value))
    return true;

à :

QString string = ...;
QStringView left = QStringView{string}.left(n);
QStringView mid = QStringView{string}.mid(n);
QStringView right = QStringView{string}.right(n);

QString value = ...;
const QList<QStringView> refs = QStringView{string}.split(u' ');
if (refs.contains(QStringView{value}))
    return true;
// or
const auto refs = QStringView{string}.tokenize(u' ');
for (auto ref : refs) {
    if (ref == value)
        return true;
}

Dans Qt 6, QRecursiveMutex n'hérite plus de QMutex. Ce changement a été effectué pour améliorer les performances de QMutex et QRecursiveMutex.

En raison de ces changements, l'enum QMutex::RecursionMode a été supprimé, et QMutexLocker est maintenant une classe modèle qui peut opérer à la fois sur QMutex et QRecursiveMutex.

La classe QFuture

Afin d'éviter l'utilisation involontaire de QFuture, l'API de QFuture a été modifiée dans Qt 6, ce qui peut entraîner des problèmes de compatibilité avec les sources.

Conversions implicites entre QFuture et d'autres types

La conversion de QFuture<T> en T a été désactivée. L'opérateur de casting appelait QFuture::result(), ce qui peut conduire à un comportement non défini si l'utilisateur a déplacé les résultats de QFuture via QFuture::takeResult() avant d'essayer d'effectuer la conversion. Utilisez explicitement les méthodes QFuture::result() ou QFuture::takeResult() lorsque vous devez convertir QFuture<T> en T.

La conversion implicite de QFuture<T> en QFuture<void> a également été désactivée. Si vous avez vraiment l'intention d'effectuer la conversion, utilisez le constructeur explicite QFuture<void>(const QFuture<T> &):

QFuture<int> future = ...
QFuture<void> voidFuture = QFuture<void>(future);

Opérateurs d'égalité

Les opérateurs d'égalité de QFuture ont été supprimés. Ils comparaient les pointeurs d sous-jacents au lieu de comparer les résultats, ce qui ne correspond pas aux attentes des utilisateurs. Si vous devez comparer des objets QFuture, utilisez les méthodes QFuture::result() ou QFuture::takeResult(). Par exemple :

QFuture<int> future1 = ...;
QFuture<int> future2 = ...;
if (future1.result() == future2.result())
    // ...

Changements de comportement de QFuture et QFutureWatcher

Dans Qt 6, des améliorations ont été apportées à QFuture et QFutureWatcher, ce qui a entraîné les changements de comportement suivants :

  • Après avoir mis en pause QFuture ou QFutureWatcher (en appelant pause() ou setPaused(true)), QFutureWatcher ne cessera pas immédiatement de fournir des signaux de progression et de résultat prêt. Au moment de la mise en pause, il se peut que des calculs soient encore en cours et ne puissent pas être arrêtés. Les signaux relatifs à ces calculs peuvent être délivrés après la pause, au lieu d'être reportés et signalés seulement après la reprise suivante. Le signal QFutureWatcher::suspended() peut être utilisé pour être informé de la prise d'effet de la pause. En outre, il existe de nouvelles méthodes isSuspending() et isSuspended(), qui permettent de vérifier si le serveur QFuture est en cours de suspension ou s'il est déjà dans l'état suspendu. Notez que pour des raisons de cohérence, pour QFuture et QFutureWatcher, les API liées à la pause ont été dépréciées et remplacées par des méthodes similaires ayant "suspend" dans le nom à la place.
  • QFuture::waitForFinished() attendra désormais que QFuture soit réellement dans l'état terminé, au lieu de sortir dès qu'il n'est pas dans l'état en cours d'exécution. Cela évite que waitForFinished() ne se termine immédiatement si, au moment où il est appelé, le futur n'est pas encore démarré. La même chose s'applique à QFutureWatcher::waitForFinished(). Ce changement n'affectera pas le comportement du code qui utilisait QFuture avec QtConcurrent. Seul le code qui l'utilisait avec le code non documenté QFutureInterface peut être affecté.
  • QFutureWatcher::isFinished() reflète maintenant l'état fini de QFuture au lieu de renvoyer false jusqu'à ce que QFutureWatcher::finished() ait été émis.

La classe QPromise

Dans Qt 6, la nouvelle classe QPromise devrait être utilisée à la place de la non officielle QFutureInterface comme contrepartie "setter" de QFuture.

Classes IO

La classe QProcess

Dans Qt XML 6, la surcharge QProcess::start() qui interprète une chaîne de commande unique en la divisant en nom de programme et en arguments est renommée en QProcess::startCommand(). Cependant, il existe une surcharge QProcess::start() qui prend une seule chaîne de caractères, ainsi qu'un paramètre QStringList pour les arguments. Comme le paramètre QStringList prend par défaut la forme d'une liste vide, le code existant qui ne transmet qu'une chaîne de caractères sera toujours compilé, mais n'exécutera pas le processus s'il s'agit d'une chaîne de commande complète comprenant des arguments.

Qt 5.15 a introduit des avertissements de dépréciation pour les surcharges respectives afin de faciliter la découverte et la mise à jour du code existant :

QProcess process;

// compiles with warnings in 5.15, compiles but fails with Qt 6
process.start("dir \"My Documents\"");

// works with both Qt 5 and Qt 6; also see QProcess::splitCommand()
process.start("dir", QStringList({"My Documents"});

// works with Qt 6
process.startCommand("dir \"My Documents\"");

QProcess::pid() et le type Q_PID ont été supprimés ; utilisez plutôt QProcess::processId() pour obtenir l'identifiant natif du processus. Le code utilisant les API Win32 natives pour accéder aux données du Q_PID en tant que structure Win32 PROCESS_INFORMATION n'est plus pris en charge.

Système de méta-types

La classe QVariant

QVariant a été réécrite pour utiliser QMetaType pour toutes ses opérations. Cela implique des changements de comportement dans quelques méthodes :

  • QVariant::isNull() QVariant ne renvoie plus que true si QVariant est vide ou contient nullptr. Dans Qt 5, elle renvoyait également vrai pour les classes de qtbase qui avaient elles-mêmes une méthode isNull si celle-ci renvoyait vrai. Le code qui s'appuie sur l'ancien comportement doit vérifier si la valeur contenue renvoie isNull - cependant, il est peu probable qu'un tel code se produise dans la pratique, car isNull() est rarement la propriété qui nous intéresse (comparez QString::isEmpty() / isNull() et QTime::isValid / isNull).
  • QVariant::operator== utilise QMetaType::equals dans Qt 6. Par conséquent, certains types qui n'ont pas d'opérateur d'égalité approprié (comme QPixmap ou QIcon) ne seront jamais comparés entre eux. De plus, les nombres à virgule flottante stockés dans QVariant ne sont plus comparés avec qFuzzyCompare, mais utilisent des comparaisons exactes.

De plus, QVariant::operator<, QVariant::operator<=, QVariant::operator> et QVariant::operator>= ont été supprimés, car les différentes variantes ne peuvent pas toujours être ordonnées. Cela signifie également que QVariant ne peut plus être utilisé comme clé dans un QMap.

La classe QMetaType

Dans Qt 6, l'enregistrement des comparateurs et des opérateurs de flux QDebug et QDataStream se fait automatiquement. Par conséquent, QMetaType::registerEqualsComparator(), QMetaType::registerComparators(), qRegisterMetaTypeStreamOperators() et QMetaType::registerDebugStreamOperator() n'existent plus. Les appels à ces méthodes doivent être supprimés lors du portage vers Qt 6.

Enregistrement des types

Les types utilisés dans Q_PROPERTY ont leur méta-type stocké dans la classe QMetaObject. Cela nécessite que les types soient complets lorsque moc les voit, ce qui peut conduire à des erreurs de compilation dans le code qui fonctionnait dans Qt 5. Il y a trois façons de résoudre ce problème :

  • Inclure l'en-tête qui définit le type.
  • Au lieu d'utiliser un include, utilisez la macro Q_MOC_INCLUDE. Cette méthode est utile si l'inclusion de l'en-tête entraîne une dépendance cyclique ou si elle ralentit la compilation.
  • Si l'en-tête est présent dans le fichier cpp qui implémente la classe, il est également possible d'y inclure le fichier généré par moc.

Classes d'expressions régulières

La classe QRegularExpression

Dans Qt 6, le type QRegExp a été retiré du module Qt5Compat et toutes les API Qt qui l'utilisaient ont été retirées des autres modules. Le code client qui l'utilisait peut être porté pour utiliser QRegularExpression à sa place. Comme QRegularExpression est déjà présent dans Qt 5, cela peut être fait et testé avant la migration vers Qt 6.

La classe QRegularExpression introduite dans Qt 5 Compatibility APIs implémente des expressions régulières compatibles avec Perl et représente une grande amélioration par rapport à QRegExp en termes d'API offertes, de syntaxe de motif prise en charge et de vitesse d'exécution. La plus grande différence est que QRegularExpression contient simplement une expression régulière et qu'elle n'est pas modifiée lorsqu'une correspondance est demandée. Au lieu de cela, un objet QRegularExpressionMatch est renvoyé pour vérifier le résultat d'une correspondance et extraire la sous-chaîne capturée. Il en va de même pour les correspondances globales et QRegularExpressionMatchIterator.

D'autres différences sont décrites ci-dessous.

Remarque : QRegularExpression ne prend pas en charge toutes les fonctionnalités disponibles dans les expressions régulières compatibles avec Perl. La plus notable est le fait que les noms dupliqués pour les groupes de capture ne sont pas pris en charge, et leur utilisation peut entraîner un comportement indéfini. Cela pourrait changer dans une future version de Qt.

Syntaxe différente des motifs

Le portage d'une expression régulière de QRegExp à QRegularExpression peut nécessiter des modifications du motif lui-même.

Dans certains cas, QRegExp a été trop indulgent et a accepté des motifs qui sont tout simplement invalides lorsqu'on utilise QRegularExpression. Ces cas sont faciles à détecter, car les objets QRegularExpression construits avec ces motifs ne sont pas valides (voir QRegularExpression::isValid()).

Dans d'autres cas, un motif porté de QRegExp à QRegularExpression peut changer silencieusement de sémantique. Il est donc nécessaire de revoir les modèles utilisés. Les cas les plus notables d'incompatibilité silencieuse sont les suivants :

  • Les accolades sont nécessaires pour utiliser un échappement hexadécimal comme \xHHHH avec plus de 2 chiffres. Un motif comme \x2022 doit être porté à \x{2022}, sinon il correspondra à un espace (0x20) suivi de la chaîne "22". En général, il est fortement recommandé de toujours utiliser des accolades avec l'échappement \x, quel que soit le nombre de chiffres spécifiés.
  • Une quantification de 0 à n comme {,n} doit être portée à {0,n} pour préserver la sémantique. Sinon, un motif tel que \d{,3} correspondrait à un chiffre suivi de la chaîne exacte "{,3}".
  • QRegExp par défaut, la correspondance tient compte de l'Unicode, tandis que QRegularExpression nécessite une option distincte ; voir ci-dessous pour plus de détails.
  • c{.} dans QRegExp correspond par défaut à tous les caractères, y compris le caractère de retour à la ligne. QRegularExpression exclut le caractère de retour à la ligne par défaut. Pour inclure le caractère de retour à la ligne, définissez l'option QRegularExpression::DotMatchesEverythingOption.

Pour une vue d'ensemble de la syntaxe des expressions régulières prises en charge par QRegularExpression, veuillez vous référer à la page de manuel pcrepattern(3), qui décrit la syntaxe des motifs prise en charge par PCRE (l'implémentation de référence des expressions régulières compatibles avec Perl).

Portage de QRegExp::exactMatch()

QRegExp::exactMatch() a deux fonctions : il fait correspondre exactement une expression régulière à une chaîne de caractères, et il implémente la correspondance partielle.

Portage de la correspondance exacte de QRegExp

La correspondance exacte indique si l'expression rationnelle correspond à la totalité de la chaîne de caractères du sujet. Par exemple, les classes produisent sur la chaîne sujet "abc123":

QRegExp::exactMatch()QRegularExpressionMatch::hasMatch()
"\\d+"fauxvrai
"[a-z]+\\d+"vraivrai

La correspondance exacte n'est pas reflétée dans QRegularExpression. Si vous voulez être sûr que la chaîne du sujet correspond exactement à l'expression régulière, vous pouvez envelopper le motif à l'aide de la fonction QRegularExpression::anchoredPattern() :

QString p("a .*|pattern");

// re matches exactly the pattern string p
QRegularExpression re(QRegularExpression::anchoredPattern(p));
Portage de la correspondance partielle de QRegExp

Lors de l'utilisation de QRegExp::exactMatch(), si une correspondance exacte n'a pas été trouvée, il est toujours possible de connaître la longueur de la chaîne du sujet correspondant à l'expression rationnelle en appelant QRegExp::matchedLength(). Si la longueur renvoyée est égale à la longueur de la chaîne de caractères, on peut en conclure qu'une correspondance partielle a été trouvée.

QRegularExpression prend en charge la correspondance partielle de manière explicite au moyen de l'adresse QRegularExpression::MatchType appropriée.

Correspondance globale

En raison des limitations de l'API QRegExp, il était impossible d'implémenter correctement la correspondance globale (c'est-à-dire comme le fait Perl). En particulier, les motifs qui peuvent correspondre à 0 caractère (comme "a*") sont problématiques.

QRegularExpression::globalMatch() implémente correctement la correspondance globale de Perl, et l'itérateur retourné peut être utilisé pour examiner chaque résultat.

Par exemple, si vous avez un code comme :

QString subject("the quick fox");

int offset = 0;
QRegExp re("(\\w+)");
while ((offset = re.indexIn(subject, offset)) != -1) {
    offset += re.matchedLength();
    // ...
}

vous pouvez le réécrire comme suit : :

QString subject("the quick fox");

QRegularExpression re("(\\w+)");
QRegularExpressionMatchIterator i = re.globalMatch(subject);
while (i.hasNext()) {
    QRegularExpressionMatch match = i.next();
    // ...
}

Prise en charge des propriétés Unicode

Lorsque vous utilisez QRegExp, les classes de caractères telles que \w, \d, etc. correspondent aux caractères ayant la propriété Unicode correspondante : par exemple, \d correspond à tout caractère ayant la propriété Unicode Nd (chiffre décimal).

Ces classes de caractères ne correspondent par défaut qu'à des caractères ASCII lors de l'utilisation de QRegularExpression: par exemple, \d correspond exactement à un caractère de la plage ASCII 0-9. Il est possible de modifier ce comportement en utilisant l'option de motif QRegularExpression::UseUnicodePropertiesOption.

Correspondance avec les caractères génériques

Il n'y a pas de moyen direct de faire des correspondances avec des caractères génériques dans QRegularExpression. Cependant, la méthode QRegularExpression::wildcardToRegularExpression() est fournie pour traduire les motifs globaux en une expression rationnelle compatible avec Perl qui peut être utilisée à cette fin.

Par exemple, si vous avez un code comme :

QRegExp wildcard("*.txt");
wildcard.setPatternSyntax(QRegExp::Wildcard);

vous pouvez le réécrire comme suit : :

auto wildcard = QRegularExpression(QRegularExpression::wildcardToRegularExpression("*.txt"));

Notez cependant que certains motifs de wildcard de type shell peuvent ne pas être traduits comme vous l'attendez. L'exemple de code suivant se cassera silencieusement s'il est simplement converti à l'aide de la fonction mentionnée ci-dessus :

const QString fp1("C:/Users/dummy/files/content.txt");
const QString fp2("/home/dummy/files/content.txt");

QRegExp re1("*/files/*");
re1.setPatternSyntax(QRegExp::Wildcard);
re1.exactMatch(fp1); // returns true
re1.exactMatch(fp2); // returns true

// but converted with QRegularExpression::wildcardToRegularExpression()

QRegularExpression re2(QRegularExpression::wildcardToRegularExpression("*/files/*"));
re2.match(fp1).hasMatch(); // returns false
re2.match(fp2).hasMatch(); // returns false

C'est parce que, par défaut, l'expression régulière retournée par QRegularExpression::wildcardToRegularExpression() est complètement ancrée. Pour obtenir une expression régulière qui n'est pas ancrée, passez QRegularExpression::UnanchoredWildcardConversion comme option de conversion :

QRegularExpression re3(QRegularExpression::wildcardToRegularExpression(
                           "*/files/*", QRegularExpression::UnanchoredWildcardConversion));
re3.match(fp1).hasMatch(); // returns true
re3.match(fp2).hasMatch(); // returns true

Correspondance minimale

QRegExp::setMinimal() implémente la correspondance minimale en inversant simplement l'avidité des quantificateurs (QRegExp ne supporte pas les quantificateurs paresseux, comme *?, +?, etc.). QRegularExpression supporte au contraire les quantificateurs avides, paresseux et possessifs. L'option QRegularExpression::InvertedGreedinessOption peut être utile pour émuler les effets de QRegExp::setMinimal() : si elle est activée, elle inverse l'avidité des quantificateurs (les quantificateurs avides deviennent paresseux et vice versa).

Modes de caret

L'option QRegularExpression::AnchorAtOffsetMatchOption match peut être utilisée pour émuler le comportement de QRegExp::CaretAtOffset. Il n'y a pas d'équivalent pour les autres modes de QRegExp::CaretMode.

La classe QRegExp

Dans Qt6, QRegExp a été retiré de Qt Core. Si votre application ne peut pas être portée maintenant, QRegExp existe toujours dans Qt5Compat pour que ces bases de code continuent de fonctionner. Si vous souhaitez utiliser davantage QRegExp, consultez la section Utilisation du module Qt5Compat.

QEvent et sous-classes

La classe QEvent a défini un constructeur de copie et un opérateur d'affectation, bien qu'il s'agisse d'une classe polymorphe. La copie de classes avec des méthodes virtuelles peut entraîner un découpage en tranches lors de l'affectation d'objets de différentes classes les uns aux autres. Comme la copie et l'affectation se font souvent de manière implicite, cela peut conduire à des problèmes difficiles à déboguer.

Dans Qt 6, le constructeur de copie et l'opérateur d'affectation pour les sous-classes de QEvent ont été protégés pour empêcher la copie implicite. Si vous devez copier des événements, utilisez la méthode clone, qui renverra une copie allouée au tas de l'objet QEvent. Assurez-vous de supprimer le clone, en utilisant par exemple std::unique_ptr, à moins que vous ne le postiez (auquel cas Qt le supprimera une fois qu'il aura été livré).

Dans vos sous-classes QEvent, surchargez clone() et déclarez le constructeur de copie et l'opérateur d'affectation protégés et implémentés par défaut comme ceci :

class MyEvent : public QEvent
{
public:
    // ...

    MyEvent *clone() const override { return new MyEvent(*this); }

protected:
    MyEvent(const MyEvent &other) = default;
    MyEvent &operator=(const MyEvent &other) = default;
    MyEvent(MyEvent &&) = delete;
    MyEvent &operator=(MyEvent &&) = delete;
    // member data
};

Notez que si votre classe MyEvent alloue de la mémoire (par exemple, par le biais d'un modèle de pointeur vers l'implémentation), vous devrez alors implémenter une sémantique de copie personnalisée.

Classes de sérialisation

Dans Qt 6, les méthodes QJsonDocument pour la conversion vers/depuis le format binaire JSON hérité de Qt ont été supprimées en faveur du format standardisé CBOR. Les types JSON de Qt peuvent être convertis en types CBOR de Qt, qui peuvent à leur tour être sérialisés dans le format binaire CBOR et vice versa. Voir, par exemple, QCborValue::fromJsonValue() et QCborValue::toJsonValue().

Si vous avez toujours besoin d'utiliser le format binaire JSON, vous pouvez utiliser les remplacements fournis dans le module Qt5Compat. Ils se trouvent dans l'espace de noms QBinaryJson. Voir Utilisation du module Qt5Compat pour savoir comment utiliser le module dans votre application.

Autres classes

Dans Qt 5, QCoreApplication::quit() était équivalent à QCoreApplication::exit(). Cela permettait de sortir de la boucle d'événements principale.

Dans Qt 6, la méthode essaiera plutôt de fermer toutes les fenêtres de niveau supérieur en affichant un événement close. Les fenêtres sont libres d'annuler le processus de fermeture en ignorant l'événement.

Appelez QCoreApplication::exit() pour conserver le comportement non conditionnel.

QLibraryInfo::location() et QLibraryInfo::Location ont été dépréciés en raison de noms incohérents. Utilisez les nouvelles API QLibraryInfo::path() et QLibraryInfo::LibraryPath à la place.

Qt State Machine Le module Framework

Qt State Machine a été déplacé dans le module Qt SCXML (qui sera bientôt renommé Qt State Machines) et ne fait donc plus partie de Qt Core. Il y avait très peu de dépendances croisées à l'intérieur de Qt Core, ce qui a finalement conduit à cette décision.

Utiliser le module Qt5Compat

Pour utiliser le module Qt5Compat, vous devez compiler avec ses en-têtes dans votre chemin d'inclusion et lier avec sa bibliothèque. Si vous utilisez qmake, ajoutez ce qui suit à votre fichier .pro:

QT += core5compat

Si vous construisez votre application ou votre bibliothèque à l'aide de cmake, ajoutez ce qui suit à votre CMakeList.txt:

PUBLIC_LIBRARIES
    Qt::Core5Compat

QTextStream

Suppression de QTextStream::setCodec(). Utilisez plutôt QTextStream::setEncoding() avec le nouvel Encoding enum.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.