Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qt6-changes.qdoc
Go to the documentation of this file.
1
// Copyright (C) 2020 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4
/*!
5
\page qtcore-changes-qt6.html
6
\title Changes to Qt Core
7
\ingroup changes-qt-5-to-6
8
\brief Changes to containers, strings, serialization and I/O classes.
9
10
Qt 6 is a result of the conscious effort to make the framework more
11
efficient and easy to use.
12
13
We try to maintain binary and source compatibility for all the public
14
APIs in each release. But some changes were inevitable in an effort to
15
make Qt a better framework.
16
17
In this topic we summarize those changes in Qt Core, and provide guidance
18
to handle them.
19
20
\section1 Container Classes
21
22
\section2 QHash, QMultiHash, QSet
23
24
\section3 qHash() Signature
25
26
For custom types, QHash and QMultiHash rely on you providing
27
a \l{qHash}{custom qHash() function}
28
in the same namespace. In Qt 4 and Qt 5, the return
29
value and optional second argument of a \c qHash function
30
was of type \c uint. In Qt 6, it is \c size_t.
31
32
That is, you need to change
33
34
\code
35
uint qHash(MyType x, uint seed);
36
\endcode
37
38
to
39
40
\code
41
size_t qHash(MyType x, size_t seed);
42
\endcode
43
44
This allows QHash, QMultiHash and QSet to hold more than 2^32 items on
45
64 bit platforms.
46
47
\section3 Stability of References
48
49
The implementation of QHash, QMultiHash and QSet in Qt 6 got changed from
50
a node based approach to a two stage lookup table. This design allows
51
to keep the memory overhead of a hash instance very small, while
52
at the same time giving good performance.
53
54
One behavioral change to note is that the new implementation
55
will not provide stable references to elements in the hash when the
56
table needs to grow, or when entries are removed. Applications that
57
rely on such stability might now run into undefined behavior.
58
59
\section3 Removal of QHash::insertMulti
60
61
In Qt 5, QHash could be used to create multi-valued hashes by using
62
QHash::insertMulti, and QMultiHash was deriving vom QHash.
63
64
In Qt 6, both types and use cases are distinct, and QHash::insertMulti
65
got removed.
66
67
\section2 QVector, QList
68
69
Prior to Qt 6, QVector and QList were separate classes. In Qt 6, they are
70
unified: Qt 5 QList implementation is gone and both classes use updated
71
QVector implementation instead. QList is the class with the actual
72
implementation and QVector is an alias (typedef) to QList.
73
74
QList's fromVector() and toVector(), and QVector's fromList() and toList(),
75
no longer involve data copying in Qt 6. They now return the object that they
76
were called for.
77
78
\section3 API Changes
79
80
QList's (and hence QVector's) size type is changed from \c int to \c
81
qsizetype. Together with the size type, all relevant methods' signatures are
82
updated to use \c qsizetype. This allows QList to hold more than 2^31 items
83
on 64 bit platforms.
84
85
When upgrading the code base to Qt 6, this API change would most likely
86
result in compiler warnings about narrowing type conversions. Having the
87
following example code:
88
89
\code
90
void myFunction(QList<MyType> &data) {
91
int size = data.size();
92
// ...
93
const int pos = getInsertPosition(size);
94
data.insert(pos, MyType());
95
// ...
96
}
97
\endcode
98
99
you would need to update it to use either \c qsizetype or an auto keyword:
100
101
\code
102
void myFunction(QList<MyType> &data) {
103
auto size = data.size();
104
// ...
105
const auto pos = getInsertPosition(size);
106
data.insert(pos, MyType());
107
// ...
108
}
109
\endcode
110
111
Alternatively, you may use type casting and cast everything to \c int or to
112
\c qsizetype.
113
114
\note If you want to build against both Qt 5 and Qt 6, the auto keyword is a
115
good solution to cover signature differences between the versions.
116
117
\section3 Memory Layout
118
119
QList received multiple changes related to the memory layout in Qt 6.
120
121
In Qt 5, \c{sizeof(QList<T>)} was equal to a size of a pointer. Now, the
122
extra pointer indirection is removed and QList data members are directly
123
stored in the object. By default, expect \c{sizeof(QList<T>)} to be equal to
124
the size of 3 pointers.
125
126
At the same time, memory layout of the elements is also updated. QList now
127
always stores its elements directly in the allocated memory region as
128
opposed to Qt 5, where certain objects were separately allocated on the heap
129
and pointers to the objects were placed into the QList instead.
130
131
Note that the latter, in particular, affects large objects. To have Qt 5
132
behavior, you could wrap your objects into smart pointers and store these
133
smart pointers in QList directly. In this case, the type of your QList would
134
be \c{QList<MySmartPointer<MyLargeObject>>} as opposed to
135
\c{QList<MyLargeObject>} in Qt 5.
136
137
\section3 Stability of References
138
139
There are several changes made to the QVector/QList implementation. The
140
QVector related one is: insertion at the beginning is optimized (similarly
141
to QList in Qt 5). The QList related one is: memory layout for the elements
142
is simplified.
143
144
\important These changes impact the stability of references. In Qt 6, you
145
should consider any size or capacity modifying method to invalidate all
146
references, even when QList is not \l{Implicit Sharing}{implicitly shared}.
147
Exceptions to this rule are documented explicitly.
148
149
Applications that rely on certain reference stability might run into
150
undefined behavior when upgraded to use Qt 6. You should pay extra attention
151
to cases where QVector or QList with a non C-compatible array layout were
152
used originally.
153
154
\section1 View classes in Qt6
155
156
\section2 General Overview
157
158
There are several new \c View classes coming with Qt6. There is the already
159
existing \l QStringView, now accompanied by \l QByteArrayView and followed
160
by a specialized \l QUtf8StringView and a more universal \l QAnyStringView.
161
162
\section2 Introduction to view classes on the example of QStringView
163
164
The QStringView class provides a unified view on UTF-16 strings with a
165
read-only subset of the QString API. Unlike QString, which keeps its own
166
copy of the string (possibly ref-counted), QStringView provides a view of
167
a string that is stored elsewhere.
168
169
\code
170
char hello[]{ "Hello." }; // narrow multi-byte string literal
171
QString str{hello}; // needs to make a copy of the string literal
172
QString strToStr(str); // atomic increment involved to not create a copy of hello again
173
174
// The above code can be re-written to avoid copying and atomic increment.
175
176
QStringView view{ u"Hello." }; // view to UTF-16 encoded string literal
177
QStringView viewToView{ view }; // view of the same UTF-16 encoded string literal
178
\endcode
179
180
The string \c "Hello." is stored in the binary and is not allocated at
181
run-time. \c view is only a view onto the string \c "Hello.", therefore
182
no copy has to be created. When we copy a QStringView, the \c viewToView
183
observes the same string as the copied-from \c view is observing. This
184
means that \c viewToView does not need to create a copy or an atomic
185
increment. They are views onto the existing string \c "Hello.".
186
187
\section2 Views as function argument
188
189
Views should be passed by value, not by reference-to-const.
190
191
\code
192
void myfun1(QStringView sv); // preferred
193
void myfun2(const QStringView &sv); // compiles and works, but slower
194
\endcode
195
196
\section2 View manipulation functions
197
198
QStringView supports functions that let us manipulate the view of the
199
string. This allows us to change the view without creating a partial copy
200
of the viewed string.
201
202
\code
203
QString pineapple = "Pineapple";
204
QString pine = pineapple.left(4);
205
206
// The above code can be re-written to avoid creating a partial copy.
207
208
QStringView pineappleView{ pineapple };
209
QStringView pineView = pineappleView.left(4);
210
\endcode
211
212
\section2 Non null-terminated strings and strings containing \c {'\0'}
213
214
QStringView supports both null-terminated and non null-terminated strings.
215
The difference comes from the way you initialize the QStringView:
216
217
\code
218
QChar aToE[]{ 'a', 'b', 'c', 'd', 'e' };
219
220
QStringView nonNull{ aToE, std::size(aToE) }; // with length given
221
QStringView nonNull{ aToE }; // automatically determines the length
222
223
QChar fToJ[]{ 'f', 'g', 'h', '\0', 'j' };
224
225
// uses given length, doesn't search for '\0', so '\0' at position 3
226
// is considered to be a part of the string similarly to 'h' and 'j
227
QStringView nonNull{ fToJ, std::size(fToJ) };
228
QStringView part{ fToJ }; //stops on the first encounter of '\0'
229
\endcode
230
231
\section2 Ownership model of views
232
233
As \c views do not own the memory they reference, care must be taken to
234
ensure that the referenced data (for example, owned by a \l QString)
235
outlives the \c view on all code paths.
236
237
\badcode
238
QStringView sayHello()
239
{
240
QString hello("Hello.");
241
return QStringView{ hello }; // hello gets out of scope and destroyed
242
}
243
244
void main()
245
{
246
QStringView hello{ sayHello() };
247
qDebug() << hello; // undefined behavior
248
}
249
\endcode
250
251
\section2 Converting an QStringView to QString
252
253
QStringView will not implicitly or explicitly convert to a QString, but can
254
create a deep copy of its data:
255
256
\code
257
void print(const QString &s) { qDebug() << s; }
258
259
void main()
260
{
261
QStringView string{ u"string"};
262
263
// print(string); // invalid, no implicit conversion
264
// QString str{ string }; // invalid, no explicit conversion
265
266
print(string.toString());
267
QString str = string.toString(); // create QString from view
268
}
269
\endcode
270
271
\section2 Important notes
272
273
By leveraging the new view classes, one can achieve a lot of performance
274
boost in many use cases. However, it is important to know that there might
275
be some caveats. Therefore it is important to remember:
276
277
\list
278
\li Views should be passed by value, not by reference-to-const.
279
\li Constructing a view with a negative length is undefined behavior.
280
\li Care must be taken to ensure that the referenced data (for example,
281
owned by a \l QString) outlives the view on all code paths.
282
\endlist
283
284
\section1 String related classes
285
286
\section2 The QStringView class
287
288
Starting with Qt6 it is generally recommended to use \l QStringView over
289
\c QStringRef. \l QStringView references a contiguous portion of a UTF-16
290
string it does not own. It acts as an interface type to all kinds of UTF-16
291
strings, without the need to construct a \l QString first. The \l QStringView
292
class exposes almost all read-only methods of \l QString and the previously
293
existing \c QStringRef class.
294
295
\note Care must be taken to ensure that the referenced string data (for
296
example, owned by a \l QString) outlives the \l QStringView on all code paths.
297
298
\note If a \l QStringView wraps a \l QString, care needs to be taken since
299
unlike \c QStringRef \l QStringView will not update the internal data pointer
300
once the \l QString data relocates.
301
302
\code
303
QString string = ...;
304
QStringView view{string};
305
306
// Appending something very long might cause a relocation and will
307
// ultimately result in a garbled QStringView.
308
string += ...;
309
\endcode
310
311
\section2 The QStringRef class
312
313
In Qt6 \l QStringRef got removed from Qt Core. To ease porting of existing
314
applications without touching the whole code-base, the \c QStringRef class
315
did not vanish completely and instead it got moved into the Qt5Compat module.
316
If you want to use \c QStringRef further, see \l {Using the Qt5Compat module}.
317
318
Unfortunately, some methods exposed by \l QString returning a \c QStringRef,
319
could not be moved to Qt5Compat. Therefore some manual porting may be
320
needed. If your code uses one or more of the following functions you need to
321
port them to use \l QStringView or \l QStringTokenizer. It is also
322
recommended to use \l {QStringView::tokenize} over \l {QStringView::split}
323
for performance critical code.
324
325
Change code using \c QStringRef:
326
\code
327
QString string = ...;
328
QStringRef left = string.leftRef(n);
329
QStringRef mid = string.midRef(n);
330
QStringRef right = string.rightRef(n);
331
332
QString value = ...;
333
const QVector<QStringRef> refs = string.splitRef(' ');
334
if (refs.contains(value))
335
return true;
336
\endcode
337
338
to:
339
340
\code
341
QString string = ...;
342
QStringView left = QStringView{string}.left(n);
343
QStringView mid = QStringView{string}.mid(n);
344
QStringView right = QStringView{string}.right(n);
345
346
QString value = ...;
347
const QList<QStringView> refs = QStringView{string}.split(u' ');
348
if (refs.contains(QStringView{value}))
349
return true;
350
// or
351
const auto refs = QStringView{string}.tokenize(u' ');
352
for (auto ref : refs) {
353
if (ref == value)
354
return true;
355
}
356
\endcode
357
358
\section1 QMutex and Related Classes
359
360
In Qt 6, QRecursiveMutex does not inherit from QMutex anymore. This change was
361
done to improve the performance of both QMutex and QRecursiveMutex.
362
363
Due to those changes, the QMutex::RecursionMode enum has been removed, and
364
QMutexLocker is now a templated class that can operate on both QMutex and
365
QRecursiveMutex.
366
367
\section1 QFuture and Related Classes
368
369
\section2 The QFuture class
370
371
To avoid unintended usage of QFuture, there were some changes to
372
QFuture API in Qt 6, which may introduce source compatibility breaks.
373
374
\section3 Implicit conversions between QFuture and other types
375
376
Conversion of \c QFuture<T> to \c T has been disabled. The casting
377
operator was calling QFuture::result(), which may lead to undefined
378
behavior if the user has moved the results from QFuture via
379
QFuture::takeResult() before trying to do the conversion. Use
380
QFuture::result() or QFuture::takeResult() methods explicitly,
381
where you need to convert \c QFuture<T> to \c T.
382
383
The implicit conversion from \c QFuture<T> to \c QFuture<void> has
384
been also disabled. If you really intend to do the conversion, use the
385
explicit \c {QFuture<void>(const QFuture<T> &)} constructor:
386
387
\code
388
QFuture<int> future = ...
389
QFuture<void> voidFuture = QFuture<void>(future);
390
\endcode
391
392
\section3 Equality operators
393
394
The equality operators of QFuture have been removed. They were comparing
395
the underlying d-pointers instead of comparing the results, which is not
396
what users might expect. If you need to compare QFuture objects, use
397
\c QFuture::result() or \c QFuture::takeResult() methods. For example:
398
399
\code
400
QFuture<int> future1 = ...;
401
QFuture<int> future2 = ...;
402
if (future1.result() == future2.result())
403
// ...
404
\endcode
405
406
\section2 Behavioral Changes to QFuture and QFutureWatcher
407
408
In Qt 6, there were some improvements to QFuture and QFutureWatcher which
409
caused the following behavioral changes:
410
411
\list
412
413
\li After pausing QFuture or QFutureWatcher (by calling \c pause() or
414
\c setPaused(true)), QFutureWatcher will not immediately stop delivering
415
progress and result ready signals. At the moment of pausing there may be
416
still computations that are in progress and cannot be stopped. Signals
417
for such computations may be still delivered after pause, instead of being
418
postponed and reported only after next resume. To get notified when pause
419
actually took effect, QFutureWatcher::suspended() signal can be used. In
420
addition, there are new \c isSuspending() and \c isSuspended() methods,
421
to check if the QFuture is in the process of suspending or it's already in
422
the suspended state. Note that for consistency reasons, for both QFuture
423
and QFutureWatcher the pause-related APIs were deprecated and replaced by
424
similar methods having "suspend" in the name instead.
425
426
\li QFuture::waitForFinished() will now wait until QFuture is actually in
427
the finished state, instead of exiting as soon as it is not in the running
428
state. This prevents \c waitForFinished() from exiting immediately, if at
429
the moment of calling it the future is not started yet. The same applies to
430
QFutureWatcher::waitForFinished(). This change won't affect the behavior of
431
code that was using QFuture with QtConcurrent. Only the code that was using
432
it with the undocumented \c QFutureInterface may be affected.
433
434
\li QFutureWatcher::isFinished() now reflects the finished-state of the
435
QFuture rather than returning false until QFutureWatcher::finished() has
436
been emitted.
437
438
\endlist
439
440
\section2 The QPromise class
441
442
In Qt 6, the new QPromise class should be used instead of unofficial
443
QFutureInterface as a "setter" counterpart of QFuture.
444
445
\section1 IO Classes
446
447
\section2 The QProcess class
448
449
In Qt 6, the QProcess::start() overload that interprets a single command string
450
by splitting it into program name and arguments is renamed to QProcess::startCommand().
451
However, a QProcess::start() overload that takes a single string, as well as a QStringList
452
for arguments exists. Since the QStringList parameter defaults to the empty list, existing
453
code only passing a string will still compile, but will fail to execute the process if it
454
is a complete command string that includes arguments.
455
456
Qt 5.15 introduced deprecation warnings for the respective overload to make it easy to
457
discover and update existing code:
458
459
\code
460
QProcess process;
461
462
// compiles with warnings in 5.15, compiles but fails with Qt 6
463
process.start("dir \"My Documents\"");
464
465
// works with both Qt 5 and Qt 6; also see QProcess::splitCommand()
466
process.start("dir", QStringList({"My Documents"});
467
468
// works with Qt 6
469
process.startCommand("dir \"My Documents\"");
470
\endcode
471
472
QProcess::pid() and the Q_PID type have been removed; use QProcess::processId() instead to
473
get the native process identifier. Code using native Win32 APIs to access the data in the
474
Q_PID as a Win32 \c{PROCESS_INFORMATION} struct is no longer supported.
475
476
\section1 Meta-Type system
477
478
\section2 The QVariant class
479
480
\c QVariant has been rewritten to use \c QMetaType for all of its operations. This implies
481
behavior changes in a few methods:
482
483
\list
484
485
\li \c QVariant::isNull() now only returns \c true if the \c QVariant is empty or contains a
486
\c nullptr. In Qt 5, it also returned true for classes in qtbase which had an \c isNull method
487
themselves if that one returned true. Code relying on the old behavior needs to check whether
488
the contained value returns isNull – however such code is unlikely to occur in practice, as
489
\c isNull() is rarely the property one is interested in (compare \c QString::isEmpty() / \c isNull()
490
and \c QTime::isValid / \c isNull).
491
492
\li \c QVariant::operator== uses \c QMetaType::equals in Qt 6. Therefore, some types
493
that lack a suitable equality operator (like \c QPixmap or \c QIcon) will
494
never compare equal. Moreover, floating
495
point numbers stored in \c QVariant are no longer compared with \c qFuzzyCompare, but instead
496
use exact comparisons.
497
498
\endlist
499
500
Furthermore, QVariant::operator<, QVariant::operator<=, QVariant::operator> and
501
QVariant::operator>= were removed, because different variants are not always orderable. This
502
also means that QVariant cannot be used anymore as a key in a QMap.
503
504
\section2 The QMetaType class
505
506
In Qt 6, registration of comparators, and QDebug and QDataStream streaming operators is
507
done automatically. Consequently, \c QMetaType::registerEqualsComparator(),
508
\c QMetaType::registerComparators(), \c qRegisterMetaTypeStreamOperators() and
509
\c QMetaType::registerDebugStreamOperator() do no longer exist. Calls to those methods
510
have to be removed when porting to Qt 6.
511
512
\section2 Type registration
513
514
Types used in \c Q_PROPERTY have their meta-type stored in the class' \c QMetaObject. This
515
requires the types to be complete when moc sees them, which can lead to compilation errors
516
in code that worked in Qt 5. There are three ways to fix this issue:
517
518
\list
519
520
\li Include the header which defines the type.
521
\li Instead of using an include, use the \c Q_MOC_INCLUDE macro. This helps if including the header
522
would cause a cyclic dependency, or when it would slow down compilation.
523
\li If the header is present in the cpp file which implements the class, it is also possible to include
524
the moc generated file there.
525
526
\endlist
527
528
\section1 Regular expression classes
529
530
\section2 The QRegularExpression class
531
532
In Qt 6, the \c QRegExp type has been retired to the Qt5Compat module
533
and all Qt APIs using it have been removed from other modules.
534
Client code which used it can be ported to use \l QRegularExpression
535
in its place. As \l QRegularExpression is present already in Qt 5,
536
this can be done and tested before migration to Qt 6.
537
538
\include corelib/port-from-qregexp.qdocinc porting-to-qregularexpression
539
540
\section2 The QRegExp class
541
542
In Qt6 \l QRegExp got removed from Qt Core. If your application cannot be
543
ported right now, \c QRegExp still exists in Qt5Compat to keep these
544
code-bases working. If you want to use \c QRegExp further, see
545
\l {Using the Qt5Compat module}.
546
547
\section1 QEvent and subclasses
548
549
The QEvent class defined a copy constructor and an assignment operator,
550
in spite of being a polymorphic class. Copying classes with virtual methods
551
can result in slicing when assigning objects from different classes to each
552
other. Since copying and assigning often happens implicilty, this could
553
lead to hard-to-debug problems.
554
555
In Qt 6, the copy constructor and assignment operator for QEvent subclasses
556
have been made protected to prevent implicit copying. If you need to copy
557
events, use the \l{QEvent::}{clone} method, which will return a heap-allocated
558
copy of the QEvent object. Make sure you delete the clone, perhaps using
559
std::unique_ptr, unless you post it (in which case Qt will delete it once it
560
has been delivered).
561
562
In your QEvent subclasses, override clone(), and declare the protected and
563
default-implemented copy constructor and assignment operator like this:
564
565
\code
566
class MyEvent : public QEvent
567
{
568
public:
569
// ...
570
571
MyEvent *clone() const override { return new MyEvent(*this); }
572
573
protected:
574
MyEvent(const MyEvent &other) = default;
575
MyEvent &operator=(const MyEvent &other) = default;
576
MyEvent(MyEvent &&) = delete;
577
MyEvent &operator=(MyEvent &&) = delete;
578
// member data
579
};
580
\endcode
581
582
Note that if your MyEvent class allocates memory (e.g. through a
583
pointer-to-implementation pattern), then you will have to implement
584
custom copy semantics.
585
586
\section1 Serialization classes
587
588
In Qt 6, QJsonDocument methods for converting it to/from Qt's legacy
589
JSON binary format were removed in favor of the standardized CBOR format.
590
Qt JSON types can be converted to Qt CBOR types, which can in turn be
591
serialized into the CBOR binary format and vice versa. See, for example,
592
\l QCborValue::fromJsonValue() and \l QCborValue::toJsonValue().
593
594
If you still need to use the binary JSON format, you can use the
595
replacements provided in the Qt5Compat module. They can be found in the
596
\l QBinaryJson namespace. See \l {Using the Qt5Compat module} to find out
597
how to use the module in your application.
598
599
\section1 Other classes
600
601
In Qt 5, QCoreApplication::quit() was equivalent to calling
602
\l{QCoreApplication::exit()}. This just exited the main event loop.
603
604
In Qt 6, the method will instead try to close all top-level windows by posting
605
a close event. The windows are free to cancel the shutdown process by
606
ignoring the event.
607
608
Call QCoreApplication::exit() to keep the non-conditional behavior.
609
610
QLibraryInfo::location() and QLibraryInfo::Location were deprecated due to inconsistent
611
naming. Use the new API QLibraryInfo::path() and QLibraryInfo::LibraryPath instead.
612
613
\section1 Qt State Machine Framework
614
615
\l {Qt State Machine} was moved into the Qt SCXML module (soon to be renamed to Qt
616
State Machines) and therefore it is no longer part of Qt Core. There were very few
617
cross dependencies inside Qt Core which ultimately led to this decision.
618
619
\section1 Using the Qt5Compat module
620
621
To use the \l {Qt 5 Core Compatibility APIs}{Qt5Compat} module, you need
622
to build with its headers in your include path and link against its library.
623
If you are using \l qmake, add the following to your \c .pro file:
624
625
\code
626
QT += core5compat
627
\endcode
628
629
If you build your application or library using \l {Build with CMake}{cmake},
630
add the following to your \c CMakeList.txt:
631
\code
632
PUBLIC_LIBRARIES
633
Qt::Core5Compat
634
\endcode
635
636
\section2 QTextStream
637
638
Removed QTextStream::setCodec().
639
Use QTextStream::setEncoding() with the new Encoding enum instead.
640
641
*/
qtbase
src
corelib
doc
src
qt6-changes.qdoc
Generated on
for Qt by
1.14.0