summaryrefslogtreecommitdiffstats
path: root/src/corelib/doc/src/qt6-changes.qdoc
blob: 0b21ecca453b6087015226df76dda48945fcfa12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \page qtcore-changes-qt6.html
    \title Changes to Qt Core
    \ingroup changes-qt-5-to-6
    \brief Migrate Qt Core to Qt 6.

    Qt 6 is a result of the conscious effort to make the framework more
    efficient and easy to use.

    We try to maintain binary and source compatibility for all the public
    APIs in each release. But some changes were inevitable in an effort to
    make Qt a better framework.

    In this topic we summarize those changes in Qt Core, and provide guidance
    to handle them.

    \section1 Container Classes

    \section2 QHash, QMultiHash, QSet

    \section3 qHash() Signature

    For custom types, QHash and QMultiHash rely on you providing
    a \l{qHash}{custom qHash() function}
    in the same namespace. In Qt 4 and Qt 5, the return
    value and optional second argument of a \c qHash function
    was of type \c uint. In Qt 6, it is \c size_t.

    That is, you need to change

    \code
    uint qHash(MyType x, uint seed);
    \endcode

    to

    \code
    size_t qHash(MyType x, size_t seed);
    \endcode

    This allows QHash, QMultiHash and QSet to hold more than 2^32 items on
    64 bit platforms.

    \section3 Stability of References

    The implementation of QHash, QMultiHash and QSet in Qt 6 got changed from
    a node based approach to a two stage lookup table. This design allows
    to keep the memory overhead of a hash instance very small, while
    at the same time giving good performance.

    One behavioral change to note is that the new implementation
    will not provide stable references to elements in the hash when the
    table needs to grow, or when entries are removed. Applications that
    rely on such stability might now run into undefined behavior.

    \section3 Removal of QHash::insertMulti

    In Qt 5, QHash could be used to create multi-valued hashes by using
    QHash::insertMulti, and QMultiHash was deriving vom QHash.

    In Qt 6, both types and use cases are distinct, and QHash::insertMulti
    got removed.

    \section2 QVector, QList

    Prior to Qt 6, QVector and QList were separate classes. In Qt 6, they are
    unified: Qt 5 QList implementation is gone and both classes use updated
    QVector implementation instead. QList is the class with the actual
    implementation and QVector is an alias (typedef) to QList.

    QList's fromVector() and toVector(), and QVector's fromList() and toList(),
    no longer involve data copying in Qt 6. They now return the object that they
    were called for.

    \section3 API Changes

    QList's (and hence QVector's) size type is changed from \c int to \c
    qsizetype. Together with the size type, all relevant methods' signatures are
    updated to use \c qsizetype. This allows QList to hold more than 2^31 items
    on 64 bit platforms.

    When upgrading the code base to Qt 6, this API change would most likely
    result in compiler warnings about narrowing type conversions. Having the
    following example code:

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

    you would need to update it to use either \c qsizetype or an auto keyword:

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

    Alternatively, you may use type casting and cast everything to \c int or to
    \c qsizetype.

    \note If you want to build against both Qt 5 and Qt 6, the auto keyword is a
    good solution to cover signature differences between the versions.

    \section3 Memory Layout

    QList received multiple changes related to the memory layout in Qt 6.

    In Qt 5, \c{sizeof(QList<T>)} was equal to a size of a pointer. Now, the
    extra pointer indirection is removed and QList data members are directly
    stored in the object. By default, expect \c{sizeof(QList<T>)} to be equal to
    the size of 3 pointers.

    At the same time, memory layout of the elements is also updated. QList now
    always stores its elements directly in the allocated memory region as
    opposed to Qt 5, where certain objects were separately allocated on the heap
    and pointers to the objects were placed into the QList instead.

    Note that the latter, in particular, affects large objects. To have Qt 5
    behavior, you could wrap your objects into smart pointers and store these
    smart pointers in QList directly. In this case, the type of your QList would
    be \c{QList<MySmartPointer<MyLargeObject>>} as opposed to
    \c{QList<MyLargeObject>} in Qt 5.

    \section3 Stability of References

    There are several changes made to the QVector/QList implementation. The
    QVector related one is: insertion at the beginning is optimized (similarly
    to QList in Qt 5). The QList related one is: memory layout for the elements
    is simplified.

    \important These changes impact the stability of references. In Qt 6, you
    should consider any size or capacity modifying method to invalidate all
    references, even when QList is not \l{Implicit Sharing}{implicitly shared}.
    Exceptions to this rule are documented explicitly.

    Applications that rely on certain reference stability might run into
    undefined behavior when upgraded to use Qt 6. You should pay extra attention
    to cases where QVector or QList with a non C-compatible array layout were
    used originally.

    \section1 View classes in Qt6

    \section2 General Overview

    There are several new \c View classes coming with Qt6. There is the already
    existing \l QStringView, now accompanied by \l QByteArrayView and followed
    by a specialized \l QUtf8StringView and a more universal \l QAnyStringView.

    \section2 Introduction to view classes on the example of QStringView

    The QStringView class provides a unified view on UTF-16 strings with a
    read-only subset of the QString API. Unlike QString, which keeps its own
    copy of the string (possibly ref-counted), QStringView provides a view of
    a string that is stored elsewhere.

    \code
        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
    \endcode

    The string \c "Hello." is stored in the binary and is not allocated at
    run-time. \c view is only a view onto the string \c "Hello.", therefore
    no copy has to be created. When we copy a QStringView, the \c viewToView
    observes the same string as the copied-from \c view is observing. This
    means that \c viewToView does not need to create a copy or an atomic
    increment. They are views onto the existing string \c "Hello.".

    \section2 Views as function argument

    Views should be passed by value, not by reference-to-const.

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

    \section2 View manipulation functions

    QStringView supports functions that let us manipulate the view of the
    string. This allows us to change the view without creating a partial copy
    of the viewed string.

    \code
        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);
    \endcode

    \section2 Non null-terminated strings and strings containing \c {'\0'}

    QStringView supports both null-terminated and non null-terminated strings.
    The difference comes from the way you initialize the QStringView:

    \code
        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'
    \endcode

    \section2 Ownership model of views

    As \c views do not own the memory they reference, care must be taken to
    ensure that the referenced data (for example, owned by a \l QString)
    outlives the \c view on all code paths.

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

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

    \section2 Converting an QStringView to QString

    QStringView will not implicitly or explicitly convert to a QString, but can
    create a deep copy of its data:

    \code
        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
        }
    \endcode

    \section2 Important notes

    By leveraging the new view classes, one can achieve a lot of performance
    boost in many use cases. However, it is important to know that there might
    be some caveats. Therefore it is important to remember:

    \list
        \li Views should be passed by value, not by reference-to-const.
        \li Constructing a view with a negative length is undefined behavior.
        \li Care must be taken to ensure that the referenced data (for example,
            owned by a \l QString) outlives the view on all code paths.
    \endlist

    \section1 String related classes

    \section2 The QStringView class

    Starting with Qt6 it is generally recommended to use \l QStringView over
    \c QStringRef. \l QStringView references a contiguous portion of a UTF-16
    string it does not own. It acts as an interface type to all kinds of UTF-16
    strings, without the need to construct a \l QString first. The \l QStringView
    class exposes almost all read-only methods of \l QString and the previously
    existing \c QStringRef class.

    \note Care must be taken to ensure that the referenced string data (for
    example, owned by a \l QString) outlives the \l QStringView on all code paths.

    \note If a \l QStringView wraps a \l QString, care needs to be taken since
    unlike \c QStringRef \l QStringView will not update the internal data pointer
    once the \l QString data relocates.

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

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

    \section2 The QStringRef class

    In Qt6 \l QStringRef got removed from Qt Core. To ease porting of existing
    applications without touching the whole code-base, the \c QStringRef class
    did not vanish completely and instead it got moved into the Qt5Compat module.

    If you want to use \c QStringRef further, you need to link against the new
    Qt5Compat module and add this line to your \l qmake \c .pro file:
    \code
        QT += core5compat
    \endcode

    In case you already ported your application or library to the
    \l {Build with CMake}{cmake} build system, add the following to your
    \c CMakeList.txt:
    \code
        PUBLIC_LIBRARIES
            Qt::Core5Compat
    \endcode

    Unfortunately, some methods exposed by \l QString returning a \c QStringRef,
    could not be moved to Qt5Compat. Therefore some manually porting may be
    needed. If your code uses one or more of the following functions you need to
    port them to use \l QStringView or \l QStringTokenizer. It is also
    recommended to use \l {QStringView::tokenize} over \l {QStringView::split}
    for performance critical code.

    Change code using \c QStringRef:
    \code
        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;
    \endcode

    to:

    \code
        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;
        }
    \endcode

    \section1 QMutex and Related Classes

    In Qt 6, QRecursiveMutex does not inherit from QMutex anymore. This change was
    done to improve the performance of both QMutex and QRecursiveMutex.

    Due to those changes, the QMutex::RecursionMode enum has been removed, and
    QMutexLocker is now a templated class that can operate on both QMutex and
    QRecursiveMutex.

    \section1 QFuture and Related Classes

    \section2 The QFuture class

    To avoid unintended usage of QFuture, there were some changes to
    QFuture API in Qt 6, which may introduce source compatibility breaks.

    \section3 Implicit conversions between QFuture and other types

    Conversion of \c QFuture<T> to \c T has been disabled. The casting
    operator was calling QFuture::result(), which may lead to undefined
    behavior if the user has moved the results from QFuture via
    QFuture::takeResult() before trying to do the conversion. Use
    QFuture::result() or QFuture::takeResult() methods explicitly,
    where you need to convert \c QFuture<T> to \c T.

    The implicit conversion from \c QFuture<T> to \c QFuture<void> has
    been also disabled. If you really intend to do the conversion, use the
    explicit \c {QFuture<void>(const QFuture<T> &)} constructor:

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

    \section3 Equality operators

    The equality operators of QFuture have been removed. They were comparing
    the underlying d-pointers instead of comparing the results, which is not
    what users might expect. If you need to compare QFuture objects, use
    \c QFuture::result() or \c QFuture::takeResult() methods. For example:

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

    \section2 Behavioral Changes to QFuture and QFutureWatcher

    In Qt 6, there were some improvements to QFuture and QFutureWatcher which
    caused the following behavioral changes:

    \list

    \li After pausing QFuture or QFutureWatcher (by calling \c pause() or
    \c setPaused(true)), QFutureWatcher will not immediately stop delivering
    progress and result ready signals. At the moment of pausing there may be
    still computations that are in progress and cannot be stopped. Signals
    for such computations may be still delivered after pause, instead of being
    postponed and reported only after next resume. To get notified when pause
    actually took effect, QFutureWatcher::suspended() signal can be used. In
    addition, there are new \c isSuspending() and \c isSuspended() methods,
    to check if the QFuture is in the process of suspending or it's already in
    the suspended state. Note that for consistency reasons, for both QFuture
    and QFutureWatcher the pause-related APIs were deprecated and replaced by
    similar methods having "suspend" in the name instead.

    \li QFuture::waitForFinished() will now wait until QFuture is actually in
    the finished state, instead of exiting as soon as it is not in the running
    state. This prevents \c waitForFinished() from exiting immediately, if at
    the moment of calling it the future is not started yet. The same applies to
    QFutureWatcher::waitForFinished(). This change won't affect the behavior of
    code that was using QFuture with QtConcurrent. Only the code that was using
    it with the undocumented \c QFutureInterface may be affected.

    \li QFutureWatcher::isFinished() now reflects the finished-state of the
    QFuture rather than returning false until QFutureWatcher::finished() has
    been emitted.

    \endlist

    \section2 The QPromise class

    In Qt 6, the new QPromise class should be used instead of unofficial
    QFutureInterface as a "setter" counterpart of QFuture.

    \section1 IO Classes

    \section2 The QProcess class

    In Qt 6, the QProcess::start() overload that interprets a single command string
    by splitting it into program name and arguments is renamed to QProcess::startCommand().
    However, a QProcess::start() overload that takes a single string, as well as a QStringList
    for arguments exists. Since the QStringList parameter defaults to the empty list, existing
    code only passing a string will still compile, but will fail to execute the process if it
    is a complete command string that includes arguments.

    Qt 5.15 introduced deprecation warnings for the respective overload to make it easy to
    discover and update existing code:

    \code
        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\"");
    \endcode

    QProcess::pid() and the Q_PID type have been removed; use QProcess::processId() instead to
    get the native process identifier. Code using native Win32 APIs to access the data in the
    Q_PID as a Win32 \c{PROCESS_INFORMATION} struct is no longer supported.

    \section1 Meta-Type system

    \section2 The QVariant class

    \c QVariant has been rewritten to use \c QMetaType for all of its operations. This implies
    behavior changes in a few methods:

    \list

    \li \c QVariant::isNull() now only returns \c true if the \c QVariant is empty or contains a
    \c nullptr. In Qt 5, it also returned true for classes in qtbase which had an \c isNull method
    themselves if that one returned true. Code relying on the old behavior needs to check whether
    the contained value returns isNull – however such code is unlikely to occur in practice, as
    \c isNull() is rarely the property one is interested in (compare \c QString::isEmpty() / \c isNull()
    and \c QTime::isValid / \c isNull).

    \li \c QVariant::operator== uses \c QMetaType::equals in Qt 6. Therefore, some graphical
    types like \c QPixmap, \c QImage and \c QIcon will never compare equal. Moreover, floating
    point numbers stored in \c QVariant are no longer compared with \c qFuzzyCompare, but instead
    use exact comparisons.

    \endlist

    Furthermore, QVariant::operator<, QVariant::operator<=, QVariant::operator> and
    QVariant::operator>= were removed, because different variants are not always orderable. This
    also means that QVariant cannot be used anymore as a key in a QMap.

    \section2 The QMetaType class

    In Qt 6, registration of comparators, and QDebug and QDataStream streaming operators is
    done automatically. Consequently, \c QMetaType::registerEqualsComparator(),
    \c QMetaType::registerComparators(), \c qRegisterMetaTypeStreamOperators() and
    \c QMetaType::registerDebugStreamOperator() do no longer exist. Calls to those methods
    have to be removed when porting to Qt 6.

    \section2 Type registration

    Types used in \c Q_PROPERTY have their meta-type stored in the class'  \c QMetaObject. This
    requires the types to be complete when moc sees them, which can lead to compilation errors
    in code that worked in Qt 5. There are three ways to fix this issue:

    \list

    \li Include the header which defines the type.
    \li Instead of using an include, use the \c Q_MOC_INCLUDE macro. This helps if including the header
        would cause a cyclic dependency, or when it would slow down compilation.
    \li If the header is present in the cpp file which implements the class, it is also possible to include
        the moc generated file there.

    \endlist

    \section1 Regular expression classes

    \section2 The QRegularExpression class

    In Qt6, all methods taking the \c QRegExp got removed from our code-base.
    Therefore it is very likely that you will have to port your application or
    library to \l QRegularExpression.

    \l QRegularExpression implements Perl-compatible regular expressions. It
    fully supports Unicode. For an overview of the regular expression syntax
    supported by \l QRegularExpression, please refer to the aforementioned
    pcrepattern(3) man page. A regular expression is made up of two things: a
    pattern string and a set of pattern options that change the meaning of the
    pattern string.

    There are some subtle differences between \l QRegularExpression and \c
    QRegExp that will be explained by this document to ease the porting effort.

    \l QRegularExpression is more strict when it comes to the syntax of the
    regular expression. Therefore it is always good to check the expression
    for \l {QRegularExpression::isValid}{validity}.

    \l QRegularExpression can almost always be declared const (except when the
    pattern changes), while \c QRegExp almost never could be.

    There is no replacement for the \l {QRegExp::CaretMode}{CaretMode}
    enumeration. The \l {QRegularExpression::AnchoredMatchOption} match option
    can be used to emulate the QRegExp::CaretAtOffset behavior. There is no
    equivalent for the other QRegExp::CaretMode modes.

    \l QRegularExpression supports only Perl-compatible regular expressions.
    Still, it does not support all the features available in Perl-compatible
    regular expressions. The most notable one is the fact that duplicated names
    for capturing groups are not supported, and using them can lead to
    undefined behavior. This may change in a future version of Qt.

    \section3 Wildcard matching

    There is no direct way to do wildcard matching in \l QRegularExpression.
    However, the \l {QRegularExpression::wildcardToRegularExpression} method
    is provided to translate glob patterns into a Perl-compatible regular
    expression that can be used for that purpose.

    \oldcode
        QRegExp wildcard("*.txt");
        wildcard.setPatternSyntax(QRegExp::Wildcard);
    \newcode
        auto wildcard = QRegularExpression(QRegularExpression::wildcardToRegularExpression("*.txt"));
    \endcode

    Please note though that not all shell like wildcard pattern might be
    translated in a way you would expect it. The following example code will
    silently break if simply converted using the above mentioned function:

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

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

        // but converted with QRegularExpression::wildcardToRegularExpression()

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

    \section3 Searching forward

    Forward searching inside a string was usually implemented with a loop using
    \c {QRegExp::indexIn} and a growing offset, but can now be easily implemented
    with \l QRegularExpressionMatchIterator or \l {QString::indexOf}.

    \oldcode
        QString subject("the quick fox");

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

        QRegularExpressionMatchIterator i = re.globalMatch(subject);
        while (i.hasNext()) {
            QRegularExpressionMatch match = i.next();
            // ...
        }

         // or alternatively using QString::indexOf

        qsizetype from = 0;
        QRegularExpressionMatch match;
        while ((from = subject.indexOf(re, from, &match)) != -1) {
            from += match.capturedLength();
            // ...
        }
    \endcode

    \section3 Searching backwards

    Backwards searching inside a string was usually often implemented as a loop
    over \c {QRegExp::lastIndexIn}, but can now be easily implemented using
    \l {QString::lastIndexOf} and \l {QRegularExpressionMatch}.

    \note \l QRegularExpressionMatchIterator is not capable of performing a
    backwards search.

    \oldcode
        int offset = -1;
        QString subject("Lorem ipsum dolor sit amet, consetetur sadipscing.");

        QRegExp re("\\s+([ids]\\w+)");
        while ((offset = re.lastIndexIn(subject, offset)) != -1) {
            --offset;
            // ...
        }
    \newcode
        qsizetype from = -1;
        QString subject("Lorem ipsum dolor sit amet, consetetur sadipscing.");

        QRegularExpressionMatch match;
        QRegularExpression re("\\s+([ids]\\w+)");
        while ((from = subject.lastIndexOf(re, from, &match)) != -1) {
            --from;
            // ...
        }
    \endcode

    \section3 exactMatch vs. match.hasMatch

    \c {QRegExp::exactMatch} served two purposes: it exactly matched a regular
    expression against a subject string, and it implemented partial matching.
    Exact matching indicates whether the regular expression matches the entire
    subject string. For example:

    \code
        QString source("abc123");

        QRegExp("\\d+").exactMatch(source);         // returns false
        QRegExp("[a-z]+\\d+").exactMatch(source);   // returns true

        QRegularExpression("\\d+").match(source).hasMatch();        // returns true
        QRegularExpression("[a-z]+\\d+").match(source).hasMatch();  // returns true
    \endcode

    Exact matching is not reflected in \l QRegularExpression. If you want to be
    sure that the subject string matches the regular expression exactly, you
    can wrap the pattern using the \l {QRegularExpression::anchoredPattern}
    function:

    \code
        QString source("abc123");

        QString pattern("\\d+");
        QRegularExpression(pattern).match(source).hasMatch();  // returns true

        pattern = QRegularExpression::anchoredPattern(pattern);
        QRegularExpression(pattern).match(source).hasMatch();  // returns false
    \endcode

    \section3 Minimal matching

    \c QRegExp::setMinimal() implemented minimal matching by simply reversing
    the greediness of the quantifiers (\c QRegExp did not support lazy
    quantifiers, like *?, +?, etc.). QRegularExpression instead does support
    greedy, lazy and possessive quantifiers. The \l
    {QRegularExpression::InvertedGreedinessOption} pattern option can be useful
    to emulate the effects of \c QRegExp::setMinimal(): if enabled, it inverts
    the greediness of quantifiers (greedy ones become lazy and vice versa).

    \section3 Different pattern syntax

    Porting a regular expression from \c QRegExp to \l QRegularExpression may
    require changes to the pattern itself. Therefore it is recommended to check
    the pattern used with the \l {QRegularExpression::isValid} method. This is
    especially important for user provided pattern or pattern not controlled by
    the developer.

    In other cases, a pattern ported from \c QRegExp to \l QRegularExpression may
    silently change semantics. Therefore, it is necessary to review the patterns
    used. The most notable cases of silent incompatibility are:

    \list
        \li Curly braces are needed in order to use a hexadecimal escape like \c
            {\xHHHH} with more than 2 digits. A pattern like \c {\x2022} needs
            to be ported to \c {\x{2022}}, or it will match a space \c {(0x20)}
            followed by the string \c {"22"}. In general, it is highly recommended
            to always use curly braces with the \c {\x} escape, no matter the
            amount of digits specified.

        \li A \c{0-to-n} quantification like \c {{,n}} needs to be ported to
            \c {{0,n}} to preserve semantics. Otherwise, a pattern such as
            \c {\d{,3}} would actually match a digit followed by the exact
            string \c {"{,3}"}.
    \endlist

    \section3 Partial Matching

    When using \c QRegExp::exactMatch(), if an exact match was not found, one
    could still find out how much of the subject string was matched by the
    regular expression by calling \c QRegExp::matchedLength(). If the returned
    length was equal to the subject string's length, then one could conclude
    that a partial match was found.
    \l QRegularExpression supports partial matching explicitly by means of the
    appropriate \l {QRegularExpression::MatchType}.

    \section3 Global matching

    Due to limitations of the \c QRegExp API it was impossible to implement
    global matching correctly (that is, like Perl does). In particular, patterns
    that can match zero characters (like "a*") are problematic. \l
    {QRegularExpression::wildcardToRegularExpression} implements Perl global
    match correctly, and the returned iterator can be used to examine each
    result.

    \section3 Unicode properties support

    When using \c QRegExp, character classes such as \c{\w}, \c{\d}, etc. match
    characters with the corresponding Unicode property: for instance, \c{\d}
    matches any character with the Unicode Nd (decimal digit) property. Those
    character classes only match ASCII characters by default. When using \l
    QRegularExpression: for instance, \c{\d} matches exactly a character in the
    0-9 ASCII range. It is possible to change this behavior by using the \l
    {QRegularExpression::UseUnicodePropertiesOption}
    pattern option.

    \section2 The QRegExp class

    In Qt6 \l QRegExp got removed from Qt Core. If your application cannot be
    ported right now, \c QRegExp still exists in Qt5Compat to keep these
    code-bases working. If you want to use \c QRegExp further, you need to link
    against the new Qt5Compat module and add this line to your \l qmake \c .pro
    file:
    \code
        QT += core5compat
    \endcode

    In case you already ported your application or library to the
    \l {Build with CMake}{cmake} build system, add the following to your
    \c CMakeList.txt:
    \code
        PUBLIC_LIBRARIES
            Qt::Core5Compat
    \endcode

    \section2 QEvent and subclasses

    The QEvent class defined a copy constructor and an assignment operator,
    in spite of being a polymorphic class. Copying classes with virtual methods
    can result in slicing when assigning objects from different classes to each
    other. Since copying and assigning often happens implicilty, this could
    lead to hard-to-debug problems.

    In Qt 6, the copy constructor and assignment operator for QEvent subclasses
    have been made protected to prevent implicit copying. If you need to copy
    events, use the \l{QEvent::}{clone} method, which will return a heap-allocated
    copy of the QEvent object. Make sure you delete the clone, perhaps using
    std::unique_ptr, unless you post it (in which case Qt will delete it once it
    has been delivered).

    In your QEvent subclasses, override clone(), and declare the protected and
    default-implemented copy constructor and assignment operator like this:

    \code
    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
    };
    \endcode

    Note that if your MyEvent class allocates memory (e.g. through a
    pointer-to-implementation pattern), then you will have to implement
    custom copy semantics.

    \section1 Other classes

    In Qt 5, QCoreApplication::quit() was equivalent to calling
    \l{QCoreApplication::exit()}. This just exited the main event loop.

    In Qt 6, the method will instead try to close all top-level windows by posting
    a close event. The windows are free to cancel the shutdown process by
    ignoring the event.

    Call QCoreApplication::exit() to keep the non-conditional behavior.

    QLibraryInfo::location() and QLibraryInfo::Location were deprecated due to inconsistent
    naming. Use the new API QLibraryInfo::path() and QLibraryInfo::LibraryPath instead.
*/