Auf dieser Seite

Änderungen an Qt Core

Qt 6 sind das Ergebnis bewusster Bemühungen, das Framework effizienter und benutzerfreundlicher zu gestalten.

Wir bemühen uns, bei jeder Version die Binär- und Quellkompatibilität für alle öffentlichen APIs zu gewährleisten. Einige Änderungen waren jedoch unvermeidlich, um Qt zu einem besseren Framework zu machen.

In diesem Thema fassen wir diese Änderungen in „ Qt Core “ zusammen und geben Hinweise zu deren Handhabung.

Container-Klassen

QHash, QMultiHash, QSet

qHash()-Signatur

Bei benutzerdefinierten Typen setzen „ QHash “ und „ QMultiHash “ voraus, dass Sie eine Funktion „ custom qHash() function “ im selben Namensraum bereitstellen. In Qt 4 und Qt 5 hatten der Rückgabewert und das optionale zweite Argument einer „ qHash “-Funktion den Typ „ uint “. In Qt 6 ist dies „ size_t “.

Das heißt, Sie müssen

uint qHash(MyType x, uint seed);

in

size_t qHash(MyType x, size_t seed);

Dadurch können „ QHash “, „ QMultiHash “ und „ QSet “ auf 64-Bit-Plattformen mehr als 2^32 Elemente enthalten.

Stabilität von Referenzen

Die Implementierung von QHash, QMultiHash und QSet in Qt 6 wurde von einem knotenbasierten Ansatz auf eine zweistufige Nachschlagetabelle umgestellt. Dieses Design ermöglicht es, den Speicher-Overhead einer Hash-Instanz sehr gering zu halten und gleichzeitig eine gute Leistung zu erzielen.

Eine zu beachtende Verhaltensänderung besteht darin, dass die neue Implementierung keine stabilen Referenzen auf Elemente im Hash bereitstellt, wenn die Tabelle vergrößert werden muss oder wenn Einträge entfernt werden. Anwendungen, die auf diese Stabilität angewiesen sind, können nun auf undefiniertes Verhalten stoßen.

Entfernung von QHash::insertMulti

In Qt 5 konnten mit „ QHash “ mithilfe von `QHash::insertMulti` mehrwertige Hashes erstellt werden, und ` QMultiHash ` leitete sich von ` QHash` ab.

In Qt 6 unterscheiden sich sowohl die Typen als auch die Anwendungsfälle, und QHash::insertMulti wurde entfernt.

QVector, QList

Vor Qt 6 waren „ QVector “ und „ QList “ separate Klassen. In Qt 6 wurden sie vereinheitlicht: Die Qt-5-Implementierung von „ QList “ wurde entfernt, und beide Klassen verwenden stattdessen die aktualisierte Implementierung von „ QVector “. „ QList “ ist die Klasse mit der eigentlichen Implementierung, und „ QVector “ ist ein Alias (typedef) für „ QList “.

QListDie Methoden `fromVector()` und `toVector()` sowie `fromList()` und `toList()` von ` QVector` beinhalten in Qt 6 keine Datenkopien mehr. Sie geben nun das Objekt zurück, für das sie aufgerufen wurden.

API-Änderungen

QListDer Typ „size“ von (und damit auch von „ QVector “) wurde von „ int “ in „ qsizetype “ geändert. Zusammen mit dem Typ „size“ wurden alle Signaturen der relevanten Methoden aktualisiert, sodass nun „ qsizetype “ verwendet wird. Dadurch kann „ QList “ auf 64-Bit-Plattformen mehr als 2^31 Elemente enthalten.

Bei einer Aktualisierung der Codebasis auf Qt 6 würde diese API-Änderung höchstwahrscheinlich zu Compiler-Warnungen bezüglich Typverengungen führen. Bei folgendem Beispielcode:

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

müssten Sie diesen so anpassen, dass entweder ` qsizetype ` oder das Schlüsselwort `auto` verwendet wird:

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

Alternativ können Sie Typumwandlungen verwenden und alles in ` int ` oder ` qsizetype` umwandeln.

Hinweis: Wenn Sie sowohl für Qt 5 als auch für Qt 6 kompilieren möchten, ist das Schlüsselwort „auto“ eine gute Lösung, um Signaturunterschiede zwischen den Versionen abzudecken.

Speicherlayout

QList erhielt in Qt 6 mehrere Änderungen in Bezug auf das Speicherlayout.

In Qt 5 entsprach „ sizeof(QList<T>) “ der Größe eines Zeigers. Nun wurde die zusätzliche Zeigerindirektion entfernt, und die Datenelemente von „ QList “ werden direkt im Objekt gespeichert. Standardmäßig entspricht „ sizeof(QList<T>) “ der Größe von 3 Zeigern.

Gleichzeitig wurde auch die Speicheranordnung der Elemente aktualisiert. „ QList “ speichert seine Elemente nun immer direkt im zugewiesenen Speicherbereich – im Gegensatz zu Qt 5, wo bestimmte Objekte separat auf dem Heap zugewiesen und stattdessen Zeiger auf die Objekte in „ QList “ abgelegt wurden.

Beachten Sie, dass insbesondere Letzteres Auswirkungen auf große Objekte hat. Um das Verhalten von Qt 5 zu erhalten, könnten Sie Ihre Objekte in Smart-Pointer verpacken und diese Smart-Pointer direkt in ` QList ` speichern. In diesem Fall wäre der Typ Ihres ` QList ` ` QList<MySmartPointer<MyLargeObject>> `, im Gegensatz zu ` QList<MyLargeObject> ` in Qt 5.

Stabilität von Referenzen

Es wurden mehrere Änderungen an der Implementierung von ` QVector` und `QList ` vorgenommen. Die Änderung in Bezug auf ` QVector ` lautet: Das Einfügen am Anfang wurde optimiert (ähnlich wie bei ` QList ` in Qt 5). Die Änderung in Bezug auf ` QList ` lautet: Das Speicherlayout für die Elemente wurde vereinfacht.

Wichtig: Diese Änderungen wirken sich auf die Stabilität von Referenzen aus. In Qt 6 sollten Sie bei jeder Methode, die die Größe oder Kapazität ändert, berücksichtigen, dass alle Referenzen ungültig werden, selbst wenn QList nicht implizit gemeinsam genutzt wird. Ausnahmen von dieser Regel sind ausdrücklich dokumentiert.

Anwendungen, die auf eine bestimmte Referenzstabilität angewiesen sind, können bei einem Upgrade auf Qt 6 zu undefiniertem Verhalten führen. Sie sollten besonders auf Fälle achten, in denen ursprünglich ` QVector ` oder ` QList ` mit einem nicht C-kompatiblen Array-Layout verwendet wurden.

Ansichtsklassen in Qt6

Allgemeiner Überblick

Mit Qt 6 werden mehrere neue „ View “-Klassen eingeführt. Neben der bereits vorhandenen „ QStringView “ gibt es nun „ QByteArrayView “, gefolgt von einer spezialisierten „ QUtf8StringView “ und einer universelleren „ QAnyStringView “.

Einführung in View-Klassen am Beispiel von QStringView

Die Klasse „ QStringView “ bietet eine einheitliche Ansicht auf UTF-16-Zeichenketten mit einer schreibgeschützten Teilmenge der „ QString “-API. Im Gegensatz zu „ QString “, das eine eigene Kopie der Zeichenkette (möglicherweise mit Referenzzählung) verwaltet, bietet „ QStringView “ eine Ansicht einer Zeichenkette, die an anderer Stelle gespeichert ist.

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

Die Zeichenkette "Hello." ist in der Binärdatei gespeichert und wird nicht zur Laufzeit zugewiesen. view ist lediglich eine Ansicht auf die Zeichenkette "Hello.", daher muss keine Kopie erstellt werden. Wenn wir eine QStringView kopieren, beobachtet die viewToView dieselbe Zeichenkette wie die view, von der kopiert wurde. Das bedeutet, dass viewToView weder eine Kopie erstellen noch eine atomare Inkrementierung vornehmen muss. Es handelt sich um Ansichten auf die vorhandene Zeichenkette "Hello.".

Ansichten als Funktionsargument

Ansichten sollten als Wert übergeben werden, nicht als Referenz auf eine Konstante.

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

Funktionen zur Manipulation von Ansichten

QStringView unterstützt Funktionen, mit denen wir die Ansicht der Zeichenkette manipulieren können. Dies ermöglicht es uns, die Ansicht zu ändern, ohne eine Teilkopie der angezeigten Zeichenkette zu erstellen.

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);

Nicht null-terminierte Zeichenfolgen und Zeichenfolgen, die '\0'

QStringView unterstützt sowohl null-terminierte als auch nicht null-terminierte Zeichenfolgen. Der Unterschied ergibt sich aus der Art und Weise, wie Sie die ` QStringView` initialisieren:

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'

Eigentumsmodell von Views

Da „ views “ keinen Besitzanspruch auf den von ihnen referenzierten Speicher haben, muss darauf geachtet werden, dass die referenzierten Daten (die beispielsweise einem „ QString “ gehören) in allen Codepfaden länger bestehen bleiben als die „ view “.

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

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

Die Konvertierung einer `QStringView` in einen `QString`

QStringView führt weder implizit noch explizit zu einer Umwandlung in eine ` QString`, kann jedoch eine tiefe Kopie ihrer Daten erzeugen:

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
}

Wichtige Hinweise

Durch die Nutzung der neuen View-Klassen lassen sich in vielen Anwendungsfällen erhebliche Leistungssteigerungen erzielen. Es ist jedoch wichtig zu wissen, dass es einige Einschränkungen geben kann. Daher ist Folgendes zu beachten:

  • Ansichten sollten als Wert übergeben werden, nicht als Referenz auf eine Konstante.
  • Das Erstellen einer Ansicht mit negativer Länge führt zu undefiniertem Verhalten.
  • Es muss darauf geachtet werden, dass die referenzierten Daten (die beispielsweise von einem ` QString` verwaltet werden) in allen Codepfaden länger bestehen bleiben als die Ansicht.

Die Klasse `QStringView`

Ab Qt6 wird generell empfohlen, „ QStringView “ anstelle von „ QStringRef “ zu verwenden. „ QStringView “ verweist auf einen zusammenhängenden Teil einer UTF-16-Zeichenkette, die nicht ihr gehört. Sie fungiert als Schnittstellentyp für alle Arten von UTF-16-Zeichenketten, ohne dass zuvor ein „ QString “ erstellt werden muss. Die Klasse „ QStringView “ stellt fast alle schreibgeschützten Methoden von „ QString “ und der zuvor vorhandenen Klasse „ QStringRef “ bereit.

Hinweis: Es muss daraufgeachtet werden, dass die referenzierten Zeichenfolgendaten (die beispielsweise einem ` QString` gehören) in allen Codepfaden länger bestehen bleiben als der ` QStringView `.

Hinweis: Wenn ein ` QStringView ` einen ` QString` umschließt, ist Vorsicht geboten, da ` QStringView ` – anders als ` QStringRef ` – den internen Datenzeiger nicht aktualisiert, sobald die Daten des ` QString ` verschoben werden.

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

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

Die Klasse `QStringRef`

In Qt6 wurde „ QStringRef “ aus „ Qt Core “ entfernt. Um die Portierung bestehender Anwendungen zu erleichtern, ohne die gesamte Codebasis zu verändern, wurde die Klasse „ QStringRef “ nicht vollständig entfernt, sondern in das Qt5Compat-Modul verschoben. Wenn Sie „ QStringRef “ weiterhin verwenden möchten, lesen Sie den Abschnitt „Verwendung des Qt5Compat-Moduls“.

Leider konnten einige von QString bereitgestellte Methoden, die einen ` QStringRef` zurückgeben, nicht in `Qt5Compat` verschoben werden. Daher ist möglicherweise eine manuelle Portierung erforderlich. Wenn Ihr Code eine oder mehrere der folgenden Funktionen verwendet, müssen Sie diese so portieren, dass sie ` QStringView ` oder ` QStringTokenizer` verwenden. Es wird außerdem empfohlen, bei leistungskritischem Code ` QStringView::tokenize ` anstelle von ` QStringView::split ` zu verwenden.

Ändern Sie den Code, der „ QStringRef “ verwendet, wie folgt:

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;

in:

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;
}

In Qt 6 erbt QRecursiveMutex nicht mehr von QMutex. Diese Änderung wurde vorgenommen, um die Leistung sowohl von QMutex als auch von QRecursiveMutex zu verbessern.

Aufgrund dieser Änderungen wurde die Enumeration `QMutex::RecursionMode` entfernt, und ` QMutexLocker ` ist nun eine Template-Klasse, die sowohl mit ` QMutex ` als auch mit ` QRecursiveMutex` arbeiten kann.

Die Klasse „QFuture“

Um eine unbeabsichtigte Verwendung von ` QFuture` zu vermeiden, wurden in Qt 6 einige Änderungen an der ` QFuture `-API vorgenommen, die zu Kompatibilitätsbrüchen auf Quellcodeebene führen können.

Implizite Konvertierungen zwischen QFuture und anderen Typen

Die Konvertierung von ` QFuture<T> ` nach ` T ` wurde deaktiviert. Der Casting-Operator rief ` QFuture::result()` auf, was zu undefiniertem Verhalten führen kann, wenn der Benutzer die Ergebnisse aus ` QFuture ` über ` QFuture::takeResult()` verschoben hat, bevor er versucht, die Konvertierung durchzuführen. Verwenden Sie explizit die Methoden ` QFuture::result()` oder ` QFuture::takeResult()`, wenn Sie ` QFuture<T> ` nach ` T` konvertieren müssen.

Die implizite Konvertierung von QFuture<T> zu QFuture<void> wurde ebenfalls deaktiviert. Wenn Sie die Konvertierung wirklich durchführen möchten, verwenden Sie den expliziten Konstruktor QFuture<void>(const QFuture<T> &):

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

Gleichheitsoperatoren

Die Gleichheitsoperatoren von ` QFuture ` wurden entfernt. Sie verglichen die zugrunde liegenden `d-Zeiger` anstatt die Ergebnisse, was nicht den Erwartungen der Benutzer entspricht. Wenn Sie ` QFuture `-Objekte vergleichen müssen, verwenden Sie die Methoden ` QFuture::result() ` oder ` QFuture::takeResult() `. Zum Beispiel:

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

Verhaltensänderungen bei QFuture und QFutureWatcher

In Qt 6 gab es einige Verbesserungen an QFuture und QFutureWatcher, die zu folgenden Verhaltensänderungen führten:

  • Nach dem Anhalten von „ QFuture “ oder „ QFutureWatcher “ (durch Aufruf von „ pause() “ oder „ setPaused(true) “) stellt „ QFutureWatcher “ die Ausgabe von Fortschritts- und Ergebnis-Signalen nicht sofort ein. Zum Zeitpunkt des Anhaltens sind möglicherweise noch Berechnungen im Gange, die nicht gestoppt werden können. Signale für solche Berechnungen werden möglicherweise auch nach der Pause noch übermittelt, anstatt verschoben und erst nach der nächsten Wiederaufnahme gemeldet zu werden. Um benachrichtigt zu werden, wenn die Pause tatsächlich wirksam geworden ist, kann das Signal ` QFutureWatcher::suspended()` verwendet werden. Darüber hinaus gibt es die neuen Methoden ` isSuspending() ` und ` isSuspended() `, um zu prüfen, ob sich das ` QFuture ` gerade im Prozess der Unterbrechung befindet oder bereits im unterbrochenen Zustand ist. Beachten Sie, dass aus Gründen der Konsistenz sowohl bei QFuture als auch bei QFutureWatcher die pausenbezogenen APIs als veraltet markiert und durch ähnliche Methoden ersetzt wurden, deren Name stattdessen „suspend“ enthält.
  • QFuture::waitForFinished() wartet nun, bis sich ` QFuture ` tatsächlich im Status „finished“ befindet, anstatt zu beenden, sobald es sich nicht mehr im Status „running“ befindet. Dies verhindert, dass ` waitForFinished() ` sofort beendet wird, wenn zum Zeitpunkt des Aufrufs das Future noch nicht gestartet ist. Das Gleiche gilt für ` QFutureWatcher::waitForFinished()`. Diese Änderung hat keine Auswirkungen auf das Verhalten von Code, der ` QFuture ` mit ` QtConcurrent` verwendet hat. Lediglich Code, der es mit der undokumentierten Methode ` QFutureInterface ` verwendet hat, ist möglicherweise betroffen.
  • QFutureWatcher::isFinished() spiegelt nun den abgeschlossenen Zustand des „ QFuture “ wider, anstatt „false“ zurückzugeben, bis „ QFutureWatcher::finished()“ ausgegeben wurde.

Die Klasse `QPromise`

In Qt 6 sollte anstelle der inoffiziellen `QFutureInterface` die neue Klasse ` QPromise ` als „Setter“-Entsprechung zu ` QFuture` verwendet werden.

IO-Klassen

Die Klasse `QProcess`

In Qt 6 wird die Überladung von ` QProcess::start()` – die eine einzelne Befehlszeichenfolge durch Aufteilung in Programmname und Argumente interpretiert – in ` QProcess::startCommand()` umbenannt. Es gibt jedoch weiterhin eine Überladung von ` QProcess::start()`, die eine einzelne Zeichenfolge entgegennimmt, sowie eine ` QStringList ` für Argumente. Da der Parameter „ QStringList “ standardmäßig auf die leere Liste gesetzt ist, lässt sich bestehender Code, der lediglich eine Zeichenkette übergibt, zwar weiterhin kompilieren, der Prozess kann jedoch nicht ausgeführt werden, wenn es sich um eine vollständige Befehlszeile handelt, die Argumente enthält.

Qt 5.15 führte Veraltungswarnungen für die entsprechende Überladung ein, um das Auffinden und Aktualisieren von bestehendem Code zu erleichtern:

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() und der Typ Q_PID wurden entfernt; verwenden Sie stattdessen QProcess::processId(), um die native Prozess-ID abzurufen. Code, der native Win32-APIs nutzt, um auf die Daten in Q_PID als Win32- PROCESS_INFORMATION -Struktur zuzugreifen, wird nicht mehr unterstützt.

Meta-Typ-System

Die Klasse `QVariant`

QVariant wurde umgeschrieben, sodass sie nun für alle ihre Operationen ` QMetaType ` verwendet. Dies hat Verhaltensänderungen bei einigen Methoden zur Folge:

  • QVariant::isNull() gibt nun nur dann „ true “ zurück, wenn die ` QVariant ` leer ist oder einen ` nullptr` enthält. In Qt 5 gab sie auch „true“ für Klassen in `qtbase` zurück, die selbst über eine ` isNull `-Methode verfügten, sofern diese „true“ zurückgab. Code, der sich auf das alte Verhalten stützt, muss prüfen, ob der enthaltene Wert `isNull` zurückgibt – allerdings ist es unwahrscheinlich, dass solcher Code in der Praxis vorkommt, da ` isNull() ` selten die Eigenschaft ist, an der man interessiert ist (vergleiche QString::isEmpty() / isNull() und QTime::isValid / isNull).
  • QVariant::operator== verwendet in Qt 6 ` QMetaType::equals `. Daher werden einige Typen, denen ein geeigneter Gleichheitsoperator fehlt (wie ` QPixmap ` oder ` QIcon`), niemals als gleich verglichen. Außerdem werden in ` QVariant ` gespeicherte Gleitkommazahlen nicht mehr mit ` qFuzzyCompare` verglichen, sondern es werden stattdessen exakte Vergleiche verwendet.

Zudem wurden QVariant::operator<, QVariant::operator<=, QVariant::operator> und QVariant::operator>= entfernt, da verschiedene Varianten nicht immer sortierbar sind. Dies bedeutet auch, dass QVariant nicht mehr als Schlüssel in einem QMap verwendet werden kann.

Die Klasse `QMetaType`

In Qt 6 erfolgt die Registrierung von Komparatoren sowie der Streaming-Operatoren „ QDebug “ und „ QDataStream “ automatisch. Folglich existieren „ QMetaType::registerEqualsComparator() “, „ QMetaType::registerComparators() “, „ qRegisterMetaTypeStreamOperators() “ und „ QMetaType::registerDebugStreamOperator() “ nicht mehr. Aufrufe dieser Methoden müssen bei der Portierung auf Qt 6 entfernt werden.

Typregistrierung

Bei Typen, die in ` Q_PROPERTY ` verwendet werden, ist ihr Metatyp in der ` QMetaObject` der Klasse gespeichert. Dies erfordert, dass die Typen vollständig sind, wenn `moc` sie erkennt, was zu Kompilierungsfehlern in Code führen kann, der unter Qt 5 noch funktioniert hat. Es gibt drei Möglichkeiten, dieses Problem zu beheben:

  • Binden Sie den Header ein, der den Typ definiert.
  • Verwenden Sie anstelle eines Include-Befehls das Makro „ Q_MOC_INCLUDE “. Dies ist hilfreich, wenn das Einbinden des Header-Dateis zu einer zyklischen Abhängigkeit führen würde oder die Kompilierung verlangsamen würde.
  • Wenn die Header-Datei in der CPP-Datei vorhanden ist, die die Klasse implementiert, ist es auch möglich, die von moc generierte Datei dort einzubinden.

Klassen für reguläre Ausdrücke

Die Klasse `QRegularExpression`

In Qt 6 wurde der Typ „ QRegExp “ in das Modul „Qt5Compat“ ausgelagert, und alle Qt-APIs, die ihn verwendeten, wurden aus anderen Modulen entfernt. Client-Code, der diesen Typ nutzte, kann so angepasst werden, dass stattdessen „ QRegularExpression “ verwendet wird. Da „ QRegularExpression “ bereits in Qt 5 vorhanden ist, kann dies vor der Migration auf Qt 6 durchgeführt und getestet werden.

Die in Qt 5 eingeführte Klasse „ QRegularExpression “ implementiert Perl-kompatible reguläre Ausdrücke und stellt hinsichtlich der angebotenen APIs, der unterstützten Mustersyntax und der Ausführungsgeschwindigkeit eine erhebliche Verbesserung gegenüber ` QRegExp ` dar. Der größte Unterschied besteht darin, dass ` QRegularExpression ` lediglich einen regulären Ausdruck enthält und bei einer Abfrage nicht verändert wird. Stattdessen wird ein ` QRegularExpressionMatch `-Objekt zurückgegeben, um das Ergebnis der Übereinstimmung zu überprüfen und die erfasste Teilzeichenfolge zu extrahieren. Dasselbe gilt für globale Übereinstimmungen und ` QRegularExpressionMatchIterator`.

Weitere Unterschiede werden im Folgenden beschrieben.

Hinweis: „ QRegularExpression “ unterstützt nicht alle Funktionen, die in Perl-kompatiblen regulären Ausdrücken verfügbar sind. Am auffälligsten ist dabei, dass doppelte Namen für Erfassungsgruppen nicht unterstützt werden und deren Verwendung zu undefiniertem Verhalten führen kann. Dies kann sich in einer zukünftigen Version von Qt XML ändern.

Unterschiedliche Mustersyntax

Die Portierung eines regulären Ausdrucks von QRegExp auf QRegularExpression erfordert möglicherweise Änderungen am Muster selbst.

In bestimmten Szenarien war QRegExp zu nachsichtig und akzeptierte Muster, die bei der Verwendung von QRegularExpression schlichtweg ungültig sind. Diese lassen sich leicht erkennen, da die mit diesen Mustern erstellten QRegularExpression -Objekte ungültig sind (siehe QRegularExpression::isValid()).

In anderen Fällen kann ein von QRegExp nach QRegularExpression portiertes Muster die Semantik unbemerkt verändern. Daher ist es notwendig, die verwendeten Muster zu überprüfen. Die auffälligsten Fälle stiller Inkompatibilität sind:

  • Für die Verwendung eines hexadezimalen Escape-Zeichens wie \xHHHH mit mehr als zwei Ziffern sind geschweifte Klammern erforderlich. Ein Muster wie \x2022 muss auf \x{2022} portiert werden, da es sonst mit einem Leerzeichen (0x20) gefolgt von der Zeichenkette "22" übereinstimmt. Generell wird dringend empfohlen, bei der Verwendung des Escape-Zeichens \x stets geschweifte Klammern zu verwenden, unabhängig von der Anzahl der angegebenen Ziffern.
  • Eine 0-bis-n-Quantifizierung wie {,n} muss in {0,n} umgewandelt werden, um die Semantik beizubehalten. Andernfalls würde ein Muster wie \d{,3} auf eine Ziffer gefolgt von genau der Zeichenkette "{,3}" passen.
  • QRegExp Standardmäßig erfolgt der Abgleich Unicode-bewusst, während QRegularExpression eine separate Option erfordert; weitere Details finden Sie weiter unten.
  • c{.} in „ QRegExp “ passt standardmäßig auf alle Zeichen, einschließlich des Zeilenumbruchzeichens. „ QRegularExpression “ schließt das Zeilenumbruchzeichen standardmäßig aus. Um das Zeilenumbruchzeichen einzubeziehen, setzen Sie die Musteroption „ QRegularExpression::DotMatchesEverythingOption “.

Einen Überblick über die von ` QRegularExpression` unterstützte Syntax für reguläre Ausdrücke finden Sie in der Manpage `pcrepattern(3) `, in der die von PCRE (der Referenzimplementierung für Perl-kompatible reguläre Ausdrücke) unterstützte Mustersyntax beschrieben wird.

Die Portierung von QRegExp::exactMatch()

QRegExp::exactMatch() diente zwei Zwecken: Es führte einen exakten Abgleich eines regulären Ausdrucks mit einer Zielzeichenfolge durch und implementierte einen teilweisen Abgleich.

Portierung aus dem exakten Abgleich von QRegExp

Der exakte Abgleich gibt an, ob der reguläre Ausdruck mit der gesamten Zielzeichenkette übereinstimmt. Beispielsweise liefern die Klassen für die Zielzeichenkette "abc123" folgende Ergebnisse:

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

Die exakte Übereinstimmung wird in ` QRegularExpression` nicht berücksichtigt. Wenn Sie sicherstellen möchten, dass die Suchzeichenfolge exakt mit dem regulären Ausdruck übereinstimmt, können Sie das Muster mit der Funktion ` QRegularExpression::anchoredPattern()` umschließen:

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

// re matches exactly the pattern string p
QRegularExpression re(QRegularExpression::anchoredPattern(p));
Portierung aus dem Bereich „Partial Matching“ von QRegExp

Bei Verwendung von ` QRegExp::exactMatch()` kann man, falls keine exakte Übereinstimmung gefunden wurde, dennoch herausfinden, wie viel der Suchzeichenfolge durch den regulären Ausdruck abgedeckt wurde, indem man ` QRegExp::matchedLength()` aufruft. Wenn die zurückgegebene Länge der Länge der Suchzeichenfolge entspricht, kann man daraus schließen, dass eine teilweise Übereinstimmung gefunden wurde.

QRegularExpression unterstützt die partielle Übereinstimmung explizit mithilfe des entsprechenden QRegularExpression::MatchType.

Globales Abgleichen

Aufgrund von Einschränkungen der QRegExp -API war es unmöglich, den globalen Abgleich korrekt zu implementieren (d. h. so, wie es Perl tut). Insbesondere sind Muster, die 0 Zeichen abgleichen können (wie "a*"), problematisch.

QRegularExpression::globalMatch() implementiert das globale Abgleichen nach Perl korrekt, und der zurückgegebene Iterator kann verwendet werden, um jedes Ergebnis zu untersuchen.

Wenn Sie beispielsweise folgenden Code haben:

QString subject("the quick fox");

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

können Sie ihn wie folgt umschreiben:

QString subject("the quick fox");

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

Unterstützung von Unicode-Eigenschaften

Bei Verwendung von ` QRegExp` passen Zeichenklassen wie ` \w`, ` \d` usw. auf Zeichen mit der entsprechenden Unicode-Eigenschaft: So passt beispielsweise ` \d ` auf jedes Zeichen mit der Unicode-Eigenschaft „ Nd “ (dezimale Ziffer).

Diese Zeichenklassen finden standardmäßig nur ASCII-Zeichen, wenn „ QRegularExpression “ verwendet wird: So findet beispielsweise „ \d “ genau ein Zeichen im ASCII-Bereich „ 0-9 “. Dieses Verhalten lässt sich mithilfe der Musteroption „ QRegularExpression::UseUnicodePropertiesOption “ ändern.

Platzhalterabgleich

In „ QRegularExpression “ gibt es keine direkte Möglichkeit, Platzhalterabgleich durchzuführen. Es steht jedoch die Methode „ QRegularExpression::wildcardToRegularExpression()“ zur Verfügung, um „glob“-Muster in einen Perl-kompatiblen regulären Ausdruck zu übersetzen, der für diesen Zweck verwendet werden kann.

Wenn Sie beispielsweise folgenden Code haben:

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

können Sie diesen wie folgt umschreiben:

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

Beachten Sie jedoch, dass einige shellähnliche Platzhaltermuster möglicherweise nicht wie erwartet übersetzt werden. Der folgende Beispielcode führt zu einem stillen Fehler, wenn er einfach mit der oben genannten Funktion konvertiert wird:

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

Dies liegt daran, dass der von ` QRegularExpression::wildcardToRegularExpression()` zurückgegebene reguläre Ausdruck standardmäßig vollständig verankert ist. Um einen regulären Ausdruck zu erhalten, der nicht verankert ist, übergeben Sie ` QRegularExpression::UnanchoredWildcardConversion ` als Konvertierungsoption:

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

Minimales Matching

QRegExp::setMinimal() implementierte die minimale Übereinstimmung, indem es einfach die Gier der Quantoren umkehrte (QRegExp unterstützte keine „lazy“-Quantoren wie *?, +? usw.). QRegularExpression unterstützt hingegen sowohl „greedy“- als auch „lazy“- und „possessive“-Quantoren. Die Option „ QRegularExpression::InvertedGreedinessOption “ kann nützlich sein, um die Auswirkungen von ` QRegExp::setMinimal()` nachzubilden: Wenn sie aktiviert ist, kehrt sie die „Gier“ der Quantoren um (gierige werden „lazy“ und umgekehrt).

Caret-Modi

Die Übereinstimmungsoption „ QRegularExpression::AnchorAtOffsetMatchOption “ kann verwendet werden, um das Verhalten von „ QRegExp::CaretAtOffset “ nachzubilden. Für die anderen „ QRegExp::CaretMode “-Modi gibt es keine Entsprechung.

Die Klasse `QRegExp`

In Qt6 wurde „ QRegExp “ aus „ Qt Core “ entfernt. Falls Ihre Anwendung derzeit nicht portiert werden kann, ist „ QRegExp “ weiterhin in „Qt5Compat“ vorhanden, um die Funktionsfähigkeit dieser Codebasen zu gewährleisten. Wenn Sie „ QRegExp “ weiterhin nutzen möchten, lesen Sie den Abschnitt „Verwendung des Qt5Compat-Moduls“.

QEvent und Unterklassen

Die Klasse „ QEvent “ definierte einen Kopierkonstruktor und einen Zuweisungsoperator, obwohl es sich um eine polymorphe Klasse handelt. Das Kopieren von Klassen mit virtuellen Methoden kann beim Zuweisen von Objekten verschiedener Klassen zueinander zu „Slicing“ führen. Da das Kopieren und Zuweisen oft implizit erfolgt, könnte dies zu schwer zu behebenden Problemen führen.

In Qt 6 wurden der Kopierkonstruktor und der Zuweisungsoperator für Unterklassen von ` QEvent ` als „protected“ deklariert, um implizites Kopieren zu verhindern. Wenn Sie Ereignisse kopieren müssen, verwenden Sie die Methode ` clone `, die eine auf dem Heap zugewiesene Kopie des ` QEvent `-Objekts zurückgibt. Stellen Sie sicher, dass Sie den Klon löschen – beispielsweise mithilfe von `std::unique_ptr` –, es sei denn, Sie versenden ihn (in diesem Fall löscht Qt ihn, sobald er zugestellt wurde).

Überschreiben Sie in Ihren Unterklassen von ` QEvent ` die Methode `clone()` und deklarieren Sie den geschützten und standardmäßig implementierten Kopierkonstruktor sowie den Zuweisungsoperator wie folgt:

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
};

Beachten Sie, dass Sie eine benutzerdefinierte Kopiersemantik implementieren müssen, wenn Ihre `MyEvent`-Klasse Speicher zuweist (z. B. über ein „Pointer-to-Implementation“-Muster).

Serialisierungs-Klassen

In Qt 6 wurden die Methoden „ QJsonDocument “ zur Konvertierung in das bzw. aus dem veralteten binären JSON-Format von Qt zugunsten des standardisierten CBOR-Formats entfernt. Qt-JSON-Typen können in Qt-CBOR-Typen konvertiert werden, die wiederum in das binäre CBOR-Format serialisiert werden können und umgekehrt. Siehe beispielsweise QCborValue::fromJsonValue() und QCborValue::toJsonValue().

Falls Sie das binäre JSON-Format weiterhin verwenden müssen, können Sie die im Qt5Compat-Modul bereitgestellten Ersatzfunktionen nutzen. Diese finden Sie im Namespace „ QBinaryJson “. Unter „Verwendung des Qt5Compat-Moduls “ erfahren Sie, wie Sie das Modul in Ihrer Anwendung einsetzen können.

Weitere Klassen

In Qt 5 entsprach der Aufruf von ` QCoreApplication::quit()` dem Aufruf von ` QCoreApplication::exit()`. Dadurch wurde lediglich die Haupt-Ereignisschleife beendet.

In Qt 6 versucht die Methode stattdessen, alle Fenster der obersten Ebene zu schließen, indem sie ein Schließereignis auslöst. Den Fenstern steht es frei, den Beendigungsvorgang abzubrechen, indem sie das Ereignis ignorieren.

Rufen Sie ` QCoreApplication::exit()` auf, um das bedingungslose Verhalten beizubehalten.

QLibraryInfo::location() und QLibraryInfo::Location wurden aufgrund uneinheitlicher Namensgebung als veraltet markiert. Verwenden Sie stattdessen die neue API QLibraryInfo::path() und QLibraryInfo::LibraryPath.

Qt State Machine Das Framework

Qt State Machine wurde in das Modul „ Qt SCXML “ (das bald in „Qt State Machine“ umbenannt wird) verschoben und ist daher nicht mehr Teil von „ Qt Core “. Innerhalb von „ Qt Core “ gab es nur sehr wenige gegenseitige Abhängigkeiten, was letztendlich zu dieser Entscheidung führte.

Verwendung des Moduls „Qt5Compat“

Um das Modul „Qt5Compat“ zu verwenden, müssen Sie beim Kompilieren dessen Header-Dateien in Ihren Include-Pfad aufnehmen und die Bibliothek einbinden. Wenn Sie qmake verwenden, fügen Sie Folgendes in Ihre Datei „ .pro “ ein:

QT += core5compat

Wenn Sie Ihre Anwendung oder Bibliothek mit cmake kompilieren, fügen Sie Folgendes zu Ihrer ` CMakeList.txt`-Datei hinzu:

PUBLIC_LIBRARIES
    Qt::Core5Compat

QTextStream

QTextStream::setCodec() wurde entfernt. Verwenden Sie stattdessen QTextStream::setEncoding() mit der neuen Enumeration „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.