Modifications apportées à Qt Core
Qt 6 résultent d’un effort délibéré visant à rendre le framework plus efficace et plus facile à utiliser.
Nous nous efforçons de maintenir la compatibilité binaire et source pour toutes les API publiques à chaque version. Cependant, certains changements étaient inévitables afin d’améliorer le framework Qt.
Dans cette rubrique, nous résumons ces modifications 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 supposent que vous fournissiez une fonction ` 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, ils sont de type ` size_t`.
Autrement dit, vous devez remplacer
par
size_t qHash(MyType x, size_t seed);Cela permet à QHash, QMultiHash et QSet de contenir plus de 2^32 éléments sur les plateformes 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 table de hachage à un niveau très faible, tout en offrant de bonnes performances.
Il convient de noter un changement de comportement : la nouvelle implémentation ne fournira pas de références stables aux éléments du hachage lorsque la table doit s'agrandir ou lorsque des entrées sont supprimées. Les applications qui reposent sur cette stabilité pourraient désormais rencontrer un comportement indéfini.
Suppression de QHash::insertMulti
Dans Qt 5, ` QHash ` pouvait être utilisé pour créer des hachages à valeurs multiples à l’aide de `QHash::insertMulti`, et ` QMultiHash ` dérivait de ` QHash`.
Dans Qt 6, les types et les 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 ont été unifiées : l’implémentation de Qt 5 QList a disparu et les deux classes utilisent désormais l’implémentation mise à jour de QVector. QList est la classe contenant l’implémentation proprement dite et QVector est un alias (typedef) de QList.
QListLes méthodes fromVector() et toVector() de ` QVector`, ainsi que les méthodes fromList() et toList() de ` `, n’impliquent plus de copie de données dans Qt 6. Elles renvoient désormais l’objet pour lequel elles ont été appelées.
Modifications de l’API
QListLe type « size » de (et donc d’ QVector) passe de « int » à « qsizetype ». Parallèlement à ce changement de type, 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 à niveau du code vers Qt 6, cette modification de l’API entraînerait très probablement des avertissements du compilateur concernant des conversions de type avec rétrécissement. Prenons l’exemple de code suivant :
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 soit ` qsizetype `, soit le mot-clé `auto` :
void myFunction(QList<MyType> &data) {
auto size = data.size();
// ...
const auto pos = getInsertPosition(size);
data.insert(pos, MyType());
// ...
}Vous pouvez également recourir à des transtypages et tout transtyper en ` int ` ou en ` qsizetype`.
Remarque : si vous souhaitez compiler à la fois pour Qt 5 et Qt 6, le mot-clé `auto` constitue une bonne solution pour pallier les différences de signature entre les versions.
Disposition de la mémoire
QList a fait l’objet de plusieurs modifications liées à l’organisation de la mémoire dans Qt 6.
Dans Qt 5, ` sizeof(QList<T>) ` était égal à la taille d’un pointeur. Désormais, l’indirection supplémentaire du pointeur a été supprimée et les membres de données ` QList ` sont directement stockés dans l’objet. Par défaut, ` sizeof(QList<T>) ` est égal à la taille de 3 pointeurs.
Parallèlement, la disposition en mémoire des éléments a également été mise à jour. QList stocke désormais toujours ses éléments directement dans la zone de mémoire allouée, contrairement à Qt 5, où certains objets étaient alloués séparément sur le tas et où des pointeurs vers ces objets étaient placés dans l’ QList à la place.
QList Notez que ce dernier point concerne en particulier les objets volumineux. Pour obtenir le comportement de Qt 5, vous pouvez encapsuler vos objets dans des pointeurs intelligents et stocker ces pointeurs intelligents directement dans l’ QList. Dans ce cas, le type de votre sera QList<MySmartPointer<MyLargeObject>>, contrairement à QList<MyLargeObject> dans Qt 5.
Stabilité des références
Plusieurs modifications ont été apportées à l’implémentation de ` QVector` / `QList `. Celle concernant ` QVector ` est la suivante : l’insertion au début est optimisée (à l’instar de ` QList ` dans Qt 5). Celle concernant ` QList ` est la suivante : la disposition en mémoire des éléments est simplifiée.
Important : ces modifications 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ée. Les exceptions à cette règle sont explicitement documentées.
Les applications qui reposent sur une certaine stabilité des références peuvent présenter un comportement indéfini lorsqu’elles sont mises à niveau pour utiliser Qt 6. Vous devez accorder une attention particulière aux cas où QVector ou QList, dont la disposition des tableaux n’est pas compatible avec le langage C, étaient utilisés à l’origine.
Classes de vue dans Qt 6
Présentation générale
Plusieurs nouvelles classes de type « View » font leur apparition dans Qt 6. Outre la classe QStringView déjà existante, on trouve désormais QByteArrayView, ainsi que la classe spécialisée QUtf8StringView et la classe plus universelle QAnyStringView.
Introduction aux classes de vue à partir de l'exemple de QStringView
La classe QStringView fournit une vue unifiée sur les 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 avec comptage de références), 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 literalLa chaîne "Hello." est stockée dans le fichier binaire et n’est pas allouée lors de l’exécution. view n’est qu’une vue sur la chaîne "Hello."; par conséquent, aucune copie ne doit être créée. Lorsque l’on copie une instance de QStringView, l’ viewToView observe la même chaîne que celle observée par l’instance view à partir de laquelle la copie a été effectuée. Cela signifie que viewToView n’a pas besoin de créer de copie ni d’effectuer d’incrémentation atomique. Il s’agit de vues sur la chaîne existante "Hello.".
Les vues en tant qu’arguments de fonction
Les vues doivent être passées par valeur, et non par référence à une constante.
void myfun1(QStringView sv); // preferred
void myfun2(const QStringView &sv); // compiles and works, but slowerFonctions de manipulation des vues
QStringView prend en charge des fonctions qui permettent de manipuler la vue de la chaîne. Cela permet de modifier la vue sans créer de copie partielle de la chaîne affichée.
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 un caractère nul et chaînes contenant '\0'
QStringView prend en charge à la fois les chaînes terminées par un caractère null et celles qui ne le sont pas. La différence réside dans la manière dont vous initialisez l’ 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 les ` views ` ne possèdent pas la mémoire à laquelle elles font référence, il faut veiller à ce que les données référencées (par exemple, détenues par une ` QString`) survivent à l’ view dans tous les chemins d’exécution.
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 n’entraîne pas de conversion implicite ou explicite 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 vue, il est possible d’obtenir un gain de performances considérable dans de nombreux cas d’utilisation. Cependant, il est important de savoir qu’il peut y avoir certaines mises en garde. Il est donc important de garder à l’esprit que :
- Les vues doivent être transmises par valeur, et non par référence à une constante.
- La construction d’une vue avec une longueur négative entraîne un comportement indéfini.
- Il faut veiller à ce que les données référencées (par exemple, celles appartenant à un ` QString`) survivent à la vue dans tous les chemins d'exécution.
Classes liées aux chaînes de caractères
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 partie contiguë d’une chaîne UTF-16 dont elle n’est pas propriétaire. Elle sert d’interface pour tous les types de chaînes UTF-16, sans qu’il soit nécessaire de créer au préalable un objet ` QString `. La classe ` QStringView ` expose la quasi-totalité des méthodes en lecture seule de ` QString ` et de l’ancienne classe ` QStringRef `.
Remarque : il convient deveiller à ce que les données de chaîne référencées (appartenant par exemple à un ` QString`) survivent à l’` QStringView ` dans tous les chemins d’exécution.
Remarque : si un QStringView encapsule un QString, il convient d'être vigilant car, contrairement à QStringRef, QStringView ne mettra pas à jour le pointeur de données interne une fois que les données de QString auront été déplacé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. Afin de faciliter le portage des applications existantes sans modifier l’ensemble du code, la classe QStringRef n’a pas complètement disparu ; elle a plutôt été déplacée dans le module Qt5Compat. Si vous souhaitez continuer à utiliser QStringRef, consultez la section Utilisation du module Qt5Compat.
Malheureusement, certaines méthodes exposées par QString et renvoyant un QStringRef n’ont pas pu être déplacées vers 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 le code où les performances sont critiques.
Modifiez 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;par :
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;
}QMutex et classes associées
Dans Qt 6, QRecursiveMutex n'hérite plus de QMutex. Ce changement a été apporté afin d'améliorer les performances de QMutex et de QRecursiveMutex.
En raison de ces modifications, l'énumération QMutex::RecursionMode a été supprimée, et QMutexLocker est désormais une classe modélisée pouvant fonctionner à la fois sur QMutex et QRecursiveMutex.
QFuture et classes associées
La classe QFuture
Afin d’éviter toute utilisation involontaire de ` QFuture`, certaines modifications ont été apportées à l’API ` QFuture ` dans Qt 6, ce qui peut entraîner des ruptures de compatibilité au niveau du code source.
Conversions implicites entre QFuture et d'autres types
La conversion de QFuture<T> en T a été désactivée. L’opérateur de transtypage appelait QFuture::result(), ce qui pouvait entraîner un comportement indéfini si l’utilisateur avait 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> vers QFuture<void> a également été désactivée. Si vous souhaitez vraiment effectuer cette conversion, utilisez le constructeur explicite QFuture<void>(const QFuture<T> &):
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 avez besoin de 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())
// ...Modifications du comportement de QFuture et QFutureWatcher
Dans Qt 6, certaines 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()ousetPaused(true)), QFutureWatcher ne cessera pas immédiatement d’émettre les signaux de progression et de résultat prêt. Au moment de la mise en pause, certains calculs peuvent encore être en cours et ne pas pouvoir être interrompus. Les signaux relatifs à ces calculs peuvent continuer à être émis après la mise en pause, au lieu d’être reportés et signalés uniquement après la reprise suivante. Pour être averti lorsque la mise en pause prend effectivement effet, il est possible d’utiliser le signal QFutureWatcher::suspended(). De plus, de nouvelles méthodesisSuspending()etisSuspended()permettent de vérifier si l’ QFuture est en cours de suspension ou si elle est déjà à l’état suspendu. Notez que, pour des raisons de cohérence, tant pour QFuture que pour QFutureWatcher, les API liées à la pause ont été dépréciées et remplacées par des méthodes similaires dont le nom comporte désormais le terme « suspend ». - QFuture::waitForFinished() attendra désormais que QFuture soit effectivement à l’état « finished », au lieu de se terminer dès qu’il n’est plus à l’état « running ». Cela empêche
waitForFinished()de se terminer immédiatement si, au moment de son appel, le « future » n’est pas encore lancé. Il en va de même pour QFutureWatcher::waitForFinished(). Ce changement n’affectera pas le comportement du code qui utilisait QFuture avec QtConcurrent. Seul le code qui l’utilisait avec la méthode non documentéeQFutureInterfacepourrait être affecté. - QFutureWatcher::isFinished() reflète désormais l’état « terminé » de l’ QFuture, au lieu de renvoyer `false` jusqu’à ce que ` QFutureWatcher::finished()` ait été émise.
La classe QPromise
Dans Qt 6, la nouvelle classe QPromise doit être utilisée à la place de l’interface non officielle QFutureInterface en tant que contrepartie « setter » de QFuture.
Classes IO
La classe QProcess
Dans Qt 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 QProcess::startCommand(). Cependant, il existe une surcharge QProcess::start() qui prend une seule chaîne, ainsi qu’une QStringList pour les arguments. Étant donné que le paramètre ` QStringList ` prend par défaut la valeur d’une liste vide, le code existant qui ne transmet qu’une chaîne de caractères continuera de se compiler, mais ne parviendra pas à exécuter 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 cette surcharge afin de faciliter la détection 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 contenues dans Q_PID sous la forme d’une structure Win32 de type « 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 dans toutes ses opérations. Cela implique des changements de comportement dans quelques méthodes :
QVariant::isNull()ne renvoie désormais `true` que si `QVariant` est vide ou contient un `nullptr`. Dans Qt 5, elle renvoyait également `true` pour les classes de `qtbase` qui disposaient elles-mêmes d’une méthode `isNull`, si celle-ci renvoyait `true`. Le code s’appuyant sur l’ancien comportement doit vérifier si la valeur contenue renvoie isNull – toutefois, un tel code est peu susceptible d’apparaître en pratique, carisNull()est rarement la propriété qui nous intéresse (comparezQString::isEmpty()/isNull()etQTime::isValid/isNull).QVariant::operator==utiliseQMetaType::equalsdans Qt 6. Par conséquent, certains types ne disposant pas d’un opérateur d’égalité adapté (commeQPixmapouQIcon) ne seront jamais considérés comme égaux. De plus, les nombres à virgule flottante stockés dansQVariantne sont plus comparés à l’aide deqFuzzyCompare, mais font l’objet de comparaisons exactes.
Par ailleurs, les opérateurs QVariant::operator<, QVariant::operator<=, QVariant::operator> et QVariant::operator>= ont été supprimés, car les différentes variantes ne sont pas toujours ordonnables. 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, ainsi que des opérateurs de flux QDebug et QDataStream, s’effectue automatiquement. Par conséquent, les méthodes 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étatype stocké dans le fichier QMetaObject de la classe. Cela nécessite que les types soient complets lorsque moc les détecte, ce qui peut entraîner des erreurs de compilation dans du code qui fonctionnait sous Qt 5. Il existe trois façons de résoudre ce problème :
- Inclure l’en-tête qui définit le type.
- Au lieu d’utiliser une inclusion, utilisez la macro «
Q_MOC_INCLUDE». Cela 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é déplacé vers le module `Qt5Compat` et toutes les API Qt qui l'utilisaient ont été supprimées des autres modules. Le code client qui l'utilisait peut être porté pour utiliser ` QRegularExpression ` à la place. Comme ` QRegularExpression ` est déjà présent dans Qt 5, cela peut être effectué et testé avant la migration vers Qt 6.
La classe ` QRegularExpression `, introduite dans Qt 5, implémente des expressions régulières compatibles avec Perl et constitue une amélioration significative par rapport à ` QRegExp ` en termes d'API proposées, de syntaxe de motifs prise en charge et de vitesse d'exécution. La principale différence réside dans le fait qu’ QRegularExpression se contente de contenir une expression régulière et n’ est pas modifiée lorsqu’une correspondance est demandée. À la place, un objet QRegularExpressionMatch est renvoyé, permettant de vérifier le résultat de la correspondance et d’extraire la sous-chaîne capturée. Il en va de même pour la correspondance globale et la fonction QRegularExpressionMatchIterator.
D'autres différences sont présentées ci-dessous.
Remarque : ` QRegularExpression ` ne prend pas en charge toutes les fonctionnalités disponibles dans les expressions régulières compatibles 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 vers QRegularExpression peut nécessiter des modifications du motif lui-même.
Dans certains cas précis, QRegExp était trop permissif et acceptait des motifs qui sont tout simplement invalides avec QRegularExpression. Ceux-ci sont faciles à détecter, car les objets ` QRegularExpression ` créés à partir de ces motifs ne sont pas valides (voir ` QRegularExpression::isValid()`).
Dans d’autres cas, un modèle porté de QRegExp vers QRegularExpression peut modifier la sémantique de manière silencieuse. Il est donc nécessaire de passer en revue les modèles utilisés. Les cas les plus notables d’incompatibilité silencieuse sont les suivants :
- Des accolades sont nécessaires pour utiliser une échappement hexadécimal tel que
\xHHHHcomportant plus de 2 chiffres. Un modèle tel que\x2022doit être porté vers\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é. - Une quantification de 0 à n telle que
{,n}doit être convertie en{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 nouvelle ligne. QRegularExpression exclut le caractère de nouvelle ligne par défaut. Pour inclure le caractère de nouvelle ligne, définissez l’option de motif QRegularExpression::DotMatchesEverythingOption.
Pour un aperçu de la syntaxe des expressions régulières prise en charge par ` QRegularExpression`, veuillez vous reporter à 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).
Le portage depuis QRegExp::exactMatch()
QRegExp::exactMatch() remplissait deux fonctions : elle effectuait une correspondance exacte entre une expression régulière et une chaîne cible, et elle implémentait la correspondance partielle.
Portage à partir de la correspondance exacte de QRegExp
La correspondance exacte indique si l’expression régulière correspond à l’intégralité de la chaîne cible. Par exemple, les classes donnent les résultats suivants sur la chaîne cible "abc123":
| QRegExp::exactMatch() | QRegularExpressionMatch::hasMatch() | |
|---|---|---|
"\\d+" | false | true |
"[a-z]+\\d+" | vrai | true |
La correspondance exacte n'est pas prise en compte dans ` QRegularExpression`. Si vous souhaitez vous assurer que la chaîne de caractères correspond exactement à l'expression régulière, vous pouvez encapsuler 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 depuis la correspondance partielle de QRegExp
Lors de l'utilisation de ` QRegExp::exactMatch()`, si aucune correspondance exacte n'a été trouvée, il est tout de même possible de déterminer la partie de la chaîne de caractères qui a été mise en correspondance avec l'expression régulière 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 explicitement en charge la correspondance partielle grâce à la fonction appropriée QRegularExpression::MatchType.
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 pouvant correspondre à 0 caractère (comme "a*") posent problème.
QRegularExpression::globalMatch() implémente correctement la correspondance globale de Perl, et l’itérateur renvoyé peut être utilisé pour examiner chaque résultat.
Par exemple, si vous avez un code tel que :
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 ainsi :
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 possédant la propriété Unicode correspondante : par exemple, \d correspond à tout caractère possédant la propriété Unicode « Nd » (chiffre décimal).
Par défaut, ces classes de caractères ne correspondent qu’aux caractères ASCII lorsqu’on utilise 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 des caractères génériques
Il n’existe pas de moyen direct d’effectuer une correspondance avec des caractères génériques dans QRegularExpression. Cependant, la méthode QRegularExpression::wildcardToRegularExpression() est fournie pour traduire les motifs glob en une expression régulière compatible avec Perl pouvant être utilisée à cette fin.
Par exemple, si vous avez un code tel que :
Vous pouvez le réécrire ainsi :
auto wildcard = QRegularExpression(QRegularExpression::wildcardToRegularExpression("*.txt"));Notez toutefois que certains motifs avec caractères génériques de type shell peuvent ne pas être convertis comme prévu. L’exemple de code suivant cessera de fonctionner sans avertissement 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 falseEn effet, par défaut, l’expression régulière renvoyée par ` QRegularExpression::wildcardToRegularExpression()` est entièrement ancrée. Pour obtenir une expression régulière non ancrée, transmettez ` QRegularExpression::UnanchoredWildcardConversion ` comme option de conversion :
QRegularExpression re3(QRegularExpression::wildcardToRegularExpression(
"*/files/*", QRegularExpression::UnanchoredWildcardConversion));
re3.match(fp1).hasMatch(); // returns true
re3.match(fp2).hasMatch(); // returns trueCorrespondance minimale
QRegExp::setMinimal() implémentait la correspondance minimale en inversant simplement la « gloutonnerie » des quantificateurs (QRegExp ne prenait pas en charge les quantificateurs paresseux, tels que *?, +?, etc.). QRegularExpression prend en revanche en charge les quantificateurs gloutons, paresseux et possessifs. L’option de modèle « QRegularExpression::InvertedGreedinessOption » peut être utile pour émuler les effets de ` QRegExp::setMinimal()` : si elle est activée, elle inverse le caractère « glouton » des quantificateurs (les quantificateurs « gloutons » deviennent « paresseux » et vice versa).
Modes « Caret »
L’option de correspondance « QRegularExpression::AnchorAtOffsetMatchOption » peut être utilisée pour émuler le comportement de « QRegExp::CaretAtOffset ». Il n’existe pas d’équivalent pour les autres modes d’ QRegExp::CaretMode.
La classe QRegExp
Dans Qt6, l’ QRegExp a été supprimé de l’ Qt Core. Si votre application ne peut pas être portée pour le moment, l’ QRegExp existe toujours dans Qt5Compat afin de garantir le fonctionnement de ces bases de code. Si vous souhaitez continuer à utiliser l’ QRegExp, consultez la section Utilisation du module Qt5Compat.
QEvent et ses sous-classes
La classe QEvent définissait un constructeur de copie et un opérateur d’affectation, bien qu’il s’agisse d’une classe polymorphe. La copie de classes comportant des méthodes virtuelles peut entraîner un « slicing » lors de l’affectation d’objets de classes différentes 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 des sous-classes de ` QEvent ` ont été rendus « protected » afin d’empêcher la copie implicite. Si vous avez besoin de copier des événements, utilisez la méthode ` clone `, qui renverra une copie de l’objet ` QEvent ` allouée sur le tas. Veillez à supprimer le clone, éventuellement à l’aide de `std::unique_ptr`, à moins que vous ne le transmettiez (auquel cas Qt le supprimera une fois qu’il aura été livré).
Dans vos sous-classes d’ QEvent, redéfinissez la méthode `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 suit :
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 via 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 permettant la conversion vers/depuis l’ancien format binaire JSON de Qt ont été supprimées au profit 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 au format binaire CBOR, et inversement. Voir, par exemple, ` QCborValue::fromJsonValue()` et ` QCborValue::toJsonValue()`.
Si vous avez tout de même besoin d’utiliser le format binaire JSON, vous pouvez utiliser les alternatives fournies dans le module Qt5Compat. Elles se trouvent dans l’espace de noms QBinaryJson. Consultez la section Utilisation du module Qt5Compat pour savoir comment utiliser ce module dans votre application.
Autres classes
Dans Qt 5, la fonction QCoreApplication::quit() équivalait à l’appel de QCoreApplication::exit(). Cela provoquait simplement la sortie de la boucle d’événements principale.
Dans Qt 6, la méthode tentera plutôt de fermer toutes les fenêtres de niveau supérieur en émettant un événement de fermeture. 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.
Les méthodes `QLibraryInfo::location()` et `QLibraryInfo::Location` ont été dépréciées en raison d'une incohérence dans la nomenclature. Utilisez plutôt les nouvelles API ` QLibraryInfo::path()` et ` QLibraryInfo::LibraryPath `.
Qt State Machine Le framework
Qt State Machine a été déplacé dans le module Qt SCXML (qui sera bientôt renommé Qt State Machine) et ne fait donc plus partie de Qt Core. Il y avait très peu de dépendances croisées au sein de Qt Core, ce qui a finalement conduit à cette décision.
Utilisation du module Qt5Compat
Pour utiliser le module Qt5Compat, vous devez effectuer la compilation en incluant ses en-têtes dans votre chemin d’inclusion et en liant votre projet à sa bibliothèque. Si vous utilisez qmake, ajoutez ce qui suit à votre fichier ` .pro ` :
QT += core5compatSi vous compilez votre application ou votre bibliothèque à l'aide de cmake, ajoutez ce qui suit à votre fichier ` CMakeList.txt` :
PUBLIC_LIBRARIES
Qt::Core5CompatQTextStream
Suppression de QTextStream::setCodec(). Utilisez plutôt QTextStream::setEncoding() avec la nouvelle énumération Encoding.
© 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.