1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Copyright (C) 2020 Intel Corporation.
5** Copyright (C) 2019 Klarälvdalens Datakonsult AB.
6** Contact: https://www.qt.io/licensing/
7**
8** This file is part of the test suite of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:GPL-EXCEPT$
11** Commercial License Usage
12** Licensees holding valid commercial Qt licenses may use this file in
13** accordance with the commercial license agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and The Qt Company. For licensing terms
16** and conditions see https://www.qt.io/terms-conditions. For further
17** information use the contact form at https://www.qt.io/contact-us.
18**
19** GNU General Public License Usage
20** Alternatively, this file may be used under the terms of the GNU
21** General Public License version 3 as published by the Free Software
22** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
23** included in the packaging of this file. Please review the following
24** information to ensure the GNU General Public License requirements will
25** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26**
27** $QT_END_LICENSE$
28**
29****************************************************************************/
30
31#define QT_SHAREDPOINTER_TRACK_POINTERS
32#include "qsharedpointer.h"
33#include <QtTest/QtTest>
34#include <QtCore/QHash>
35#include <QtCore/QMap>
36#include <QtCore/QThread>
37#include <QtCore/QVector>
38
39#include "externaltests.h"
40#include "forwarddeclared.h"
41#include "nontracked.h"
42#include "wrapper.h"
43
44#include <array>
45#include <memory>
46#include <stdlib.h>
47#include <time.h>
48
49#ifdef Q_OS_UNIX
50#include <sys/resource.h>
51#endif
52
53QT_BEGIN_NAMESPACE
54namespace QtSharedPointer {
55 Q_CORE_EXPORT void internalSafetyCheckCleanCheck();
56}
57QT_END_NAMESPACE
58
59class tst_QSharedPointer: public QObject
60{
61 Q_OBJECT
62
63private slots:
64 void initTestCase();
65 void basics_data();
66 void basics();
67 void operators();
68 void nullptrOps();
69 void swap();
70 void moveSemantics();
71 void useOfForwardDeclared();
72 void memoryManagement();
73 void dropLastReferenceOfForwardDeclared();
74 void nonVirtualDestructors();
75 void lock();
76 void downCast();
77 void functionCallDownCast();
78 void upCast();
79 void qobjectWeakManagement();
80#if QT_DEPRECATED_SINCE(5, 0)
81 void noSharedPointerFromWeakQObject();
82 void sharedPointerFromQObjectWithWeak();
83#endif
84 void weakQObjectFromSharedPointer();
85 void objectCast();
86 void objectCastStdSharedPtr();
87 void differentPointers();
88 void virtualBaseDifferentPointers();
89#ifndef QTEST_NO_RTTI
90 void dynamicCast();
91 void dynamicCastDifferentPointers();
92 void dynamicCastVirtualBase();
93 void dynamicCastFailure();
94 void dynamicCastFailureNoLeak();
95#endif
96 void constCorrectness();
97 void customDeleter();
98 void lambdaCustomDeleter();
99 void customDeleterOnNullptr();
100 void creating();
101 void creatingCvQualified();
102 void creatingVariadic();
103 void creatingQObject();
104 void mixTrackingPointerCode();
105 void reentrancyWhileDestructing();
106 void map();
107 void hash();
108 void qvariantCast();
109 void sharedFromThis();
110
111 void constructorThrow();
112 void overloads();
113
114 void threadStressTest_data();
115 void threadStressTest();
116 void validConstructs();
117 void invalidConstructs_data();
118 void invalidConstructs();
119
120
121 // let invalidConstructs be the last test, because it's the slowest;
122 // add new tests above this block
123public slots:
124 void cleanup() { safetyCheck(); }
125
126public:
127 inline void safetyCheck()
128 {
129#ifdef QT_BUILD_INTERNAL
130 QtSharedPointer::internalSafetyCheckCleanCheck();
131#endif
132 }
133};
134
135void tst_QSharedPointer::initTestCase()
136{
137#if defined(Q_OS_UNIX)
138 // The tests create a lot of threads, which require file descriptors. On systems like
139 // OS X low defaults such as 256 as the limit for the number of simultaneously
140 // open files is not sufficient.
141 struct rlimit numFiles;
142 if (getrlimit(RLIMIT_NOFILE, rlimits: &numFiles) == 0 && numFiles.rlim_cur < 1024) {
143 numFiles.rlim_cur = qMin(a: rlim_t(1024), b: numFiles.rlim_max);
144 setrlimit(RLIMIT_NOFILE, rlimits: &numFiles);
145 }
146#endif
147}
148
149template<typename T> static inline
150QtSharedPointer::ExternalRefCountData *refCountData(const QSharedPointer<T> &b)
151{
152 // access d-pointer:
153 struct Dummy {
154 void* value;
155 QtSharedPointer::ExternalRefCountData* data;
156 };
157 // sanity checks:
158 Q_STATIC_ASSERT(sizeof(QSharedPointer<T>) == sizeof(Dummy));
159 Q_ASSERT(static_cast<const Dummy*>(static_cast<const void*>(&b))->value == b.data());
160 return static_cast<const Dummy*>(static_cast<const void*>(&b))->data;
161}
162
163class Data
164{
165public:
166 static int destructorCounter;
167 static int generationCounter;
168 int generation;
169
170 Data() : generation(++generationCounter)
171 { }
172
173 virtual ~Data()
174 {
175 if (generation <= 0)
176 qFatal(msg: "tst_qsharedpointer: Double deletion!");
177 generation = 0;
178 ++destructorCounter;
179 }
180
181 void doDelete()
182 {
183 delete this;
184 }
185
186 bool alsoDelete()
187 {
188 doDelete();
189 return true;
190 }
191
192 virtual void virtualDelete()
193 {
194 delete this;
195 }
196
197 virtual int classLevel() { return 1; }
198};
199int Data::generationCounter = 0;
200int Data::destructorCounter = 0;
201
202struct NoDefaultConstructor1
203{
204 int i;
205 NoDefaultConstructor1(int i) : i(i) {}
206 NoDefaultConstructor1(uint j) : i(j + 42) {}
207};
208
209struct NoDefaultConstructorRef1
210{
211 int &i;
212 NoDefaultConstructorRef1(int &i) : i(i) {}
213};
214
215struct NoDefaultConstructor2
216{
217 void *ptr;
218 int i;
219 NoDefaultConstructor2(void *ptr, int i) : ptr(ptr), i(i) {}
220};
221
222struct NoDefaultConstructorRef2
223{
224 QString str;
225 int i;
226 NoDefaultConstructorRef2(QString &str, int i) : str(str), i(i) {}
227};
228
229struct NoDefaultConstructorConstRef2
230{
231 QString str;
232 int i;
233 NoDefaultConstructorConstRef2(const QString &str, int i) : str(str), i(i) {}
234 NoDefaultConstructorConstRef2(const QByteArray &ba, int i = 42) : str(QString::fromLatin1(str: ba)), i(i) {}
235};
236
237struct NoDefaultConstructorRRef1
238{
239 int &i;
240 NoDefaultConstructorRRef1(int &&i) : i(i) {}
241};
242
243struct NoDefaultConstructorRRef2
244{
245 std::unique_ptr<int> i;
246 NoDefaultConstructorRRef2(std::unique_ptr<int> &&i) : i(std::move(i)) {}
247};
248
249void tst_QSharedPointer::basics_data()
250{
251 QTest::addColumn<bool>(name: "isNull");
252 QTest::newRow(dataTag: "null") << true;
253 QTest::newRow(dataTag: "non-null") << false;
254}
255
256void tst_QSharedPointer::basics()
257{
258 {
259 QSharedPointer<Data> ptr;
260 QWeakPointer<Data> weakref;
261
262 QCOMPARE(sizeof(ptr), 2*sizeof(void*));
263 QCOMPARE(sizeof(weakref), 2*sizeof(void*));
264 }
265
266 {
267 QSharedPointer<const Data> ptr;
268 QWeakPointer<const Data> weakref;
269
270 QCOMPARE(sizeof(ptr), 2*sizeof(void*));
271 QCOMPARE(sizeof(weakref), 2*sizeof(void*));
272 }
273
274 QFETCH(bool, isNull);
275 Data *aData = 0;
276 if (!isNull)
277 aData = new Data;
278 Data *otherData = new Data;
279 QSharedPointer<Data> ptr(aData);
280
281 {
282 // basic self tests
283 QCOMPARE(ptr.isNull(), isNull);
284 QCOMPARE(bool(ptr), !isNull);
285 QCOMPARE(!ptr, isNull);
286
287 QCOMPARE(ptr.data(), aData);
288 QCOMPARE(ptr.get(), aData);
289 QCOMPARE(ptr.operator->(), aData);
290 if (!isNull) {
291 Data &dataReference = *ptr;
292 QCOMPARE(&dataReference, aData);
293 }
294
295 QVERIFY(ptr == aData);
296 QVERIFY(!(ptr != aData));
297 QVERIFY(aData == ptr);
298 QVERIFY(!(aData != ptr));
299
300 QVERIFY(ptr != otherData);
301 QVERIFY(otherData != ptr);
302 QVERIFY(! (ptr == otherData));
303 QVERIFY(! (otherData == ptr));
304 }
305 QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1);
306 QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1);
307
308 {
309 // create another object:
310 QSharedPointer<Data> otherCopy(otherData);
311 QVERIFY(ptr != otherCopy);
312 QVERIFY(otherCopy != ptr);
313 QVERIFY(! (ptr == otherCopy));
314 QVERIFY(! (otherCopy == ptr));
315
316 // otherData is deleted here
317 }
318 QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1);
319 QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1);
320
321 {
322 // create a copy:
323 QSharedPointer<Data> copy(ptr);
324 QVERIFY(copy == ptr);
325 QVERIFY(ptr == copy);
326 QVERIFY(! (copy != ptr));
327 QVERIFY(! (ptr != copy));
328 QCOMPARE(copy, ptr);
329 QCOMPARE(ptr, copy);
330
331 QCOMPARE(copy.isNull(), isNull);
332 QCOMPARE(copy.data(), aData);
333 QCOMPARE(copy.get(), aData);
334 QVERIFY(copy == aData);
335 }
336 QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1);
337 QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1);
338
339 {
340 // create a weak reference:
341 QWeakPointer<Data> weak(ptr);
342 QCOMPARE(weak.isNull(), isNull);
343 QCOMPARE(!weak, isNull);
344 QCOMPARE(bool(weak), !isNull);
345
346 QVERIFY(ptr == weak);
347 QVERIFY(weak == ptr);
348 QVERIFY(! (ptr != weak));
349 QVERIFY(! (weak != ptr));
350
351 // create another reference:
352 QWeakPointer<Data> weak2(weak);
353 QCOMPARE(weak2.isNull(), isNull);
354 QCOMPARE(!weak2, isNull);
355 QCOMPARE(bool(weak2), !isNull);
356
357 QVERIFY(weak2 == weak);
358 QVERIFY(weak == weak2);
359 QVERIFY(! (weak2 != weak));
360 QVERIFY(! (weak != weak2));
361
362 // create a strong reference back:
363 QSharedPointer<Data> strong(weak);
364 QVERIFY(strong == weak);
365 QVERIFY(strong == ptr);
366 QCOMPARE(strong.data(), aData);
367 QCOMPARE(strong.get(), aData);
368 }
369 QVERIFY(!refCountData(ptr) || refCountData(ptr)->weakref.loadRelaxed() == 1);
370 QVERIFY(!refCountData(ptr) || refCountData(ptr)->strongref.loadRelaxed() == 1);
371
372 // aData is deleted here
373}
374
375void tst_QSharedPointer::operators()
376{
377 QSharedPointer<char> p1;
378 QSharedPointer<char> p2(new char);
379 qptrdiff diff = p2.data() - p1.data();
380 QVERIFY(p1.data() != p2.data());
381 QVERIFY(p1.get() != p2.get());
382 QVERIFY(diff != 0);
383
384 // operator-
385 QCOMPARE(p2 - p1.data(), diff);
386 QCOMPARE(p2 - p1.get(), diff);
387 QCOMPARE(p2.data() - p1, diff);
388 QCOMPARE(p2.get() - p1, diff);
389 QCOMPARE(p2 - p1, diff);
390 QCOMPARE(p1 - p2, -diff);
391 QCOMPARE(p1 - p1, qptrdiff(0));
392 QCOMPARE(p2 - p2, qptrdiff(0));
393
394 // operator<
395 QVERIFY(p1 < p2.data());
396 QVERIFY(p1 < p2.get());
397 QVERIFY(p1.data() < p2);
398 QVERIFY(p1.get() < p2);
399 QVERIFY(p1 < p2);
400 QVERIFY(!(p2 < p1));
401 QVERIFY(!(p2 < p2));
402 QVERIFY(!(p1 < p1));
403
404 // qHash
405 QCOMPARE(qHash(p1), qHash(p1.data()));
406 QCOMPARE(qHash(p1), qHash(p1.get()));
407 QCOMPARE(qHash(p2), qHash(p2.data()));
408 QCOMPARE(qHash(p2), qHash(p2.get()));
409}
410
411void tst_QSharedPointer::nullptrOps()
412{
413 QSharedPointer<char> p1(nullptr);
414 QSharedPointer<char> p2 = nullptr;
415 QSharedPointer<char> null;
416
417 QVERIFY(p1 == null);
418 QVERIFY(p1 == nullptr);
419 QVERIFY(nullptr == p1);
420 QVERIFY(!p1);
421 QVERIFY(!p1.data());
422 QVERIFY(!p1.get());
423 QVERIFY(p2 == null);
424 QVERIFY(p2 == nullptr);
425 QVERIFY(nullptr == p2);
426 QVERIFY(!p2);
427 QVERIFY(!p2.data());
428 QVERIFY(!p2.get());
429 QVERIFY(p1 == p2);
430
431 QSharedPointer<char> p3 = p1;
432 QVERIFY(p3 == p1);
433 QVERIFY(p3 == null);
434 QVERIFY(p3 == nullptr);
435 QVERIFY(nullptr == p3);
436 QVERIFY(!p3.data());
437 QVERIFY(!p3.get());
438
439 p3 = nullptr;
440
441 // check for non-ambiguity
442 QSharedPointer<char> p1_zero(0);
443 QSharedPointer<char> p2_zero = 0;
444
445 p3 = 0;
446
447 QSharedPointer<char> p4(new char);
448 QVERIFY(p4);
449 QVERIFY(p4.data());
450 QVERIFY(p4.get());
451 QVERIFY(p4 != nullptr);
452 QVERIFY(nullptr != p4);
453 QVERIFY(p4 != p1);
454 QVERIFY(p4 != p2);
455 QVERIFY(p4 != null);
456 QVERIFY(p4 != p3);
457}
458
459void tst_QSharedPointer::swap()
460{
461 QSharedPointer<int> p1, p2(new int(42)), control = p2;
462 QVERIFY(p1 != control);
463 QVERIFY(p1.isNull());
464 QVERIFY(p2 == control);
465 QVERIFY(!p2.isNull());
466 QVERIFY(*p2 == 42);
467
468 p1.swap(other&: p2);
469 QVERIFY(p1 == control);
470 QVERIFY(!p1.isNull());
471 QVERIFY(p2 != control);
472 QVERIFY(p2.isNull());
473 QVERIFY(*p1 == 42);
474
475 p1.swap(other&: p2);
476 QVERIFY(p1 != control);
477 QVERIFY(p1.isNull());
478 QVERIFY(p2 == control);
479 QVERIFY(!p2.isNull());
480 QVERIFY(*p2 == 42);
481
482 qSwap(value1&: p1, value2&: p2);
483 QVERIFY(p1 == control);
484 QVERIFY(!p1.isNull());
485 QVERIFY(p2 != control);
486 QVERIFY(p2.isNull());
487 QVERIFY(*p1 == 42);
488
489 QWeakPointer<int> w1, w2 = control;
490
491 QVERIFY(w1.isNull());
492 QVERIFY(!w2.isNull());
493 QVERIFY(w2.lock() == control);
494 QVERIFY(!w1.lock());
495
496 w1.swap(other&: w2);
497 QVERIFY(w2.isNull());
498 QVERIFY(!w1.isNull());
499 QVERIFY(w1.lock() == control);
500 QVERIFY(!w2.lock());
501
502 qSwap(value1&: w1, value2&: w2);
503 QVERIFY(w1.isNull());
504 QVERIFY(w2.lock() == control);
505
506 p1.reset();
507 p2.reset();
508 control.reset();
509
510 QVERIFY(w1.isNull());
511 QVERIFY(w2.isNull());
512}
513
514void tst_QSharedPointer::moveSemantics()
515{
516 QSharedPointer<int> p1, p2(new int(42)), control = p2;
517 QVERIFY(p1 != control);
518 QVERIFY(p1.isNull());
519 QVERIFY(p2 == control);
520 QVERIFY(!p2.isNull());
521 QVERIFY(*p2 == 42);
522
523 // move assignment
524 p1 = std::move(p2);
525 QVERIFY(p1 == control);
526 QVERIFY(!p1.isNull());
527 QVERIFY(p2 != control);
528 QVERIFY(p2.isNull());
529 QVERIFY(*p1 == 42);
530
531 // move construction
532 QSharedPointer<int> p3 = std::move(p1);
533 QVERIFY(p1 != control);
534 QVERIFY(p1.isNull());
535 QVERIFY(p3 == control);
536 QVERIFY(!p3.isNull());
537 QVERIFY(*p3 == 42);
538
539 QWeakPointer<int> w1, w2 = control;
540
541 QVERIFY(w1.isNull());
542 QVERIFY(!w2.isNull());
543 QVERIFY(w2.lock() == control);
544 QVERIFY(!w1.lock());
545
546 // move assignment
547 w1 = std::move(w2);
548 QVERIFY(w2.isNull());
549 QVERIFY(!w1.isNull());
550 QVERIFY(w1.lock() == control);
551 QVERIFY(!w2.lock());
552
553 // move construction
554 QWeakPointer<int> w3 = std::move(w1);
555 QVERIFY(w1.isNull());
556 QVERIFY(!w3.isNull());
557 QVERIFY(w3.lock() == control);
558 QVERIFY(!w1.lock());
559
560 p1.reset();
561 p2.reset();
562 p3.reset();
563 control.reset();
564
565 QVERIFY(w1.isNull());
566 QVERIFY(w2.isNull());
567 QVERIFY(w3.isNull());
568}
569
570void tst_QSharedPointer::useOfForwardDeclared()
571{
572 // this just a compile test: use the forward-declared class
573 QSharedPointer<ForwardDeclared> sp;
574
575 // copying should work, too:
576 QSharedPointer<ForwardDeclared> sp2 = sp;
577
578 // and assignment:
579 QSharedPointer<ForwardDeclared> sp3;
580 sp3 = sp;
581
582 // move assignment:
583 QSharedPointer<ForwardDeclared> sp4;
584 sp4 = std::move(sp);
585
586 // and move constuction:
587 QSharedPointer<ForwardDeclared> sp5 = std::move(sp2);
588
589 // swapping:
590 sp4.swap(other&: sp3);
591 qSwap(value1&: sp4, value2&: sp3);
592
593 // and, of course, destruction
594}
595
596
597void tst_QSharedPointer::memoryManagement()
598{
599 int generation = Data::generationCounter + 1;
600 int destructorCounter = Data::destructorCounter;
601
602 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data);
603 QCOMPARE(ptr->generation, generation);
604 QCOMPARE(Data::destructorCounter, destructorCounter);
605 QCOMPARE(Data::generationCounter, generation);
606
607 ptr = ptr;
608 QCOMPARE(ptr->generation, generation);
609 QCOMPARE(Data::destructorCounter, destructorCounter);
610 QCOMPARE(Data::generationCounter, generation);
611
612 {
613 QSharedPointer<Data> copy = ptr;
614 QCOMPARE(ptr->generation, generation);
615 QCOMPARE(copy->generation, generation);
616
617 // copy goes out of scope, ptr continues
618 }
619 QCOMPARE(ptr->generation, generation);
620 QCOMPARE(Data::destructorCounter, destructorCounter);
621 QCOMPARE(Data::generationCounter, generation);
622
623 {
624 QWeakPointer<Data> weak = ptr;
625 weak = ptr;
626 QCOMPARE(ptr->generation, generation);
627 QCOMPARE(Data::destructorCounter, destructorCounter);
628 QCOMPARE(Data::generationCounter, generation);
629
630 weak = weak;
631 QCOMPARE(ptr->generation, generation);
632 QCOMPARE(Data::destructorCounter, destructorCounter);
633 QCOMPARE(Data::generationCounter, generation);
634
635 QSharedPointer<Data> strong = weak;
636 QCOMPARE(ptr->generation, generation);
637 QCOMPARE(strong->generation, generation);
638 QCOMPARE(Data::destructorCounter, destructorCounter);
639 QCOMPARE(Data::generationCounter, generation);
640
641 // both weak and strong go out of scope
642 }
643 QCOMPARE(ptr->generation, generation);
644 QCOMPARE(Data::destructorCounter, destructorCounter);
645 QCOMPARE(Data::generationCounter, generation);
646
647 QWeakPointer<Data> weak = ptr;
648 ptr = QSharedPointer<Data>();
649
650 // destructor must have been called
651 QCOMPARE(Data::destructorCounter, destructorCounter + 1);
652 QVERIFY(ptr.isNull());
653 QVERIFY(weak.isNull());
654
655 // if we create a strong pointer from the weak, it must still be null
656 ptr = weak;
657 QVERIFY(ptr.isNull());
658 QVERIFY(ptr == 0);
659 QCOMPARE(ptr.data(), (Data*)0);
660}
661
662void tst_QSharedPointer::dropLastReferenceOfForwardDeclared()
663{
664 // pointer to shared-pointer is weird, but we need to do it so that
665 // we can drop the last reference in a different .cpp than where it was created
666 forwardDeclaredDestructorRunCount = 0;
667 delete forwardPointer();
668 QCOMPARE(forwardDeclaredDestructorRunCount, 1);
669}
670
671// NVD for "non-virtual destructor"
672struct NVDData
673{
674 static int destructorCounter;
675 ~NVDData() { ++destructorCounter; }
676
677 int dummy;
678};
679int NVDData::destructorCounter;
680
681struct NVDDerivedData : NVDData
682{
683 static int destructorCounter;
684 ~NVDDerivedData() { ++destructorCounter; }
685};
686int NVDDerivedData::destructorCounter;
687
688void tst_QSharedPointer::nonVirtualDestructors()
689{
690 NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
691 {
692 QSharedPointer<NVDData> ptr(new NVDData);
693 }
694 QCOMPARE(NVDData::destructorCounter, 1);
695 QCOMPARE(NVDDerivedData::destructorCounter, 0);
696
697 NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
698 {
699 QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData);
700 }
701 QCOMPARE(NVDData::destructorCounter, 1);
702 QCOMPARE(NVDDerivedData::destructorCounter, 1);
703
704 NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
705 {
706 QSharedPointer<NVDData> bptr;
707 QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData);
708 bptr = ptr;
709 }
710 QCOMPARE(NVDData::destructorCounter, 1);
711 QCOMPARE(NVDDerivedData::destructorCounter, 1);
712
713 NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
714 {
715 QSharedPointer<NVDData> ptr(new NVDDerivedData);
716 }
717 QCOMPARE(NVDData::destructorCounter, 1);
718 QCOMPARE(NVDDerivedData::destructorCounter, 1);
719}
720
721void tst_QSharedPointer::lock()
722{
723 QSharedPointer<int> sp = QSharedPointer<int>::create();
724 QVERIFY(sp);
725 QWeakPointer<int> wp = sp;
726 QVERIFY(sp == wp);
727 QVERIFY(sp == wp.lock());
728 QVERIFY(sp == wp.toStrongRef());
729
730 sp.reset();
731 QVERIFY(!wp);
732 QVERIFY(sp != wp); // this is why op(shared_ptr, weak_ptr) is a bad idea (apart from MT races)...
733 QVERIFY(sp == wp.lock());
734 QVERIFY(sp == wp.toStrongRef());
735}
736
737class DerivedData: public Data
738{
739public:
740 static int derivedDestructorCounter;
741 int moreData;
742 DerivedData() : moreData(0) { }
743 ~DerivedData() { ++derivedDestructorCounter; }
744
745 virtual void virtualDelete()
746 {
747 delete this;
748 }
749
750 virtual int classLevel() { return 2; }
751};
752int DerivedData::derivedDestructorCounter = 0;
753
754class Stuffing
755{
756public:
757 char buffer[16];
758 Stuffing() { for (uint i = 0; i < sizeof buffer; ++i) buffer[i] = 16 - i; }
759 virtual ~Stuffing() { }
760};
761
762class DiffPtrDerivedData: public Stuffing, public Data
763{
764public:
765 virtual int classLevel() { return 3; }
766};
767
768class VirtualDerived: virtual public Data
769{
770public:
771 int moreData;
772
773 VirtualDerived() : moreData(0xc0ffee) { }
774 virtual int classLevel() { return 4; }
775};
776
777void tst_QSharedPointer::downCast()
778{
779 {
780 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
781 QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(src: ptr);
782 QSharedPointer<Data> other;
783
784 QVERIFY(ptr == baseptr);
785 QVERIFY(baseptr == ptr);
786 QVERIFY(! (ptr != baseptr));
787 QVERIFY(! (baseptr != ptr));
788
789 QVERIFY(ptr != other);
790 QVERIFY(other != ptr);
791 QVERIFY(! (ptr == other));
792 QVERIFY(! (other == ptr));
793 }
794
795 {
796 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
797 QSharedPointer<Data> baseptr = ptr;
798 }
799
800 int destructorCount;
801 destructorCount = DerivedData::derivedDestructorCounter;
802 {
803 QSharedPointer<Data> baseptr;
804 {
805 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
806 baseptr = ptr;
807 QVERIFY(baseptr == ptr);
808 }
809 }
810 QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
811
812 destructorCount = DerivedData::derivedDestructorCounter;
813 {
814 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
815 QWeakPointer<Data> baseptr = ptr;
816 QVERIFY(baseptr == ptr);
817
818 ptr = QSharedPointer<DerivedData>();
819 QVERIFY(baseptr.isNull());
820 }
821 QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
822
823 destructorCount = DerivedData::derivedDestructorCounter;
824 {
825 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData);
826 QWeakPointer<DerivedData> weakptr(ptr);
827
828 QSharedPointer<Data> baseptr = weakptr;
829 QVERIFY(baseptr == ptr);
830 QWeakPointer<Data> baseweakptr = weakptr;
831 QVERIFY(baseweakptr == ptr);
832 }
833 QCOMPARE(DerivedData::derivedDestructorCounter, destructorCount + 1);
834}
835
836void functionDataByValue(QSharedPointer<Data> p) { Q_UNUSED(p); };
837void functionDataByRef(const QSharedPointer<Data> &p) { Q_UNUSED(p); };
838void tst_QSharedPointer::functionCallDownCast()
839{
840 QSharedPointer<DerivedData> p(new DerivedData());
841 functionDataByValue(p);
842 functionDataByRef(p);
843}
844
845void tst_QSharedPointer::upCast()
846{
847 QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);
848
849 {
850 QSharedPointer<DerivedData> derivedptr = qSharedPointerCast<DerivedData>(src: baseptr);
851 QVERIFY(baseptr == derivedptr);
852 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
853 }
854 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
855 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
856
857 {
858 QWeakPointer<DerivedData> derivedptr = qWeakPointerCast<DerivedData>(src: baseptr);
859 QVERIFY(baseptr == derivedptr);
860 }
861 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
862 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
863
864 {
865 QWeakPointer<Data> weakptr = baseptr;
866 QSharedPointer<DerivedData> derivedptr = qSharedPointerCast<DerivedData>(src: weakptr);
867 QVERIFY(baseptr == derivedptr);
868 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
869 }
870 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
871 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
872
873 {
874 QSharedPointer<DerivedData> derivedptr = baseptr.staticCast<DerivedData>();
875 QVERIFY(baseptr == derivedptr);
876 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
877 }
878 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
879 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
880}
881
882class OtherObject: public QObject
883{
884 Q_OBJECT
885};
886
887void tst_QSharedPointer::qobjectWeakManagement()
888{
889 {
890 QWeakPointer<QObject> weak;
891 weak = QWeakPointer<QObject>();
892 QVERIFY(weak.isNull());
893 QVERIFY(weak.toStrongRef().isNull());
894 }
895
896 {
897 QObject *obj = new QObject;
898 QSharedPointer<QObject> shared(obj);
899 QWeakPointer<QObject> weak(shared);
900 QVERIFY(!weak.isNull());
901 QVERIFY(weak.toStrongRef() == obj);
902
903 // now delete
904 shared.reset();
905 QVERIFY(weak.isNull());
906 }
907 safetyCheck();
908
909 {
910 // same, bit with operator=
911 QObject *obj = new QObject;
912 QSharedPointer<QObject> shared(obj);
913 QWeakPointer<QObject> weak;
914 weak = shared;
915 QVERIFY(!weak.isNull());
916 QVERIFY(weak.toStrongRef() == obj);
917
918 // now delete
919 shared.reset();
920 QVERIFY(weak.isNull());
921 }
922 safetyCheck();
923
924 {
925 // with two QWeakPointers
926 QObject *obj = new QObject;
927 QSharedPointer<QObject> shared(obj);
928 QWeakPointer<QObject> weak(shared);
929
930 {
931 QWeakPointer<QObject> weak2(shared);
932 QVERIFY(!weak2.isNull());
933 QVERIFY(weak == weak2);
934 }
935 QVERIFY(!weak.isNull());
936
937 shared.reset();
938 QVERIFY(weak.isNull());
939 }
940 safetyCheck();
941
942 {
943 // same, but delete the pointer while two QWeakPointers exist
944 QObject *obj = new QObject;
945 QSharedPointer<QObject> shared(obj);
946 QWeakPointer<QObject> weak(shared);
947
948 {
949 QWeakPointer<QObject> weak2(shared);
950 QVERIFY(!weak2.isNull());
951
952 shared.reset();
953 QVERIFY(weak.isNull());
954 QVERIFY(weak2.isNull());
955 }
956 QVERIFY(weak.isNull());
957 }
958 safetyCheck();
959
960#if QT_DEPRECATED_SINCE(5, 0)
961 {
962 QWeakPointer<QObject> weak;
963 weak = QWeakPointer<QObject>();
964 QVERIFY(weak.isNull());
965 QVERIFY(!weak.data());
966 }
967
968 {
969 QObject *obj = new QObject;
970 QWeakPointer<QObject> weak(obj);
971 QVERIFY(!weak.isNull());
972 QVERIFY(weak.data() == obj);
973
974 // now delete
975 delete obj;
976 QVERIFY(weak.isNull());
977 }
978 safetyCheck();
979
980 {
981 // same, bit with operator=
982 QObject *obj = new QObject;
983 QWeakPointer<QObject> weak;
984 weak = obj;
985 QVERIFY(!weak.isNull());
986 QVERIFY(weak.data() == obj);
987
988 // now delete
989 delete obj;
990 QVERIFY(weak.isNull());
991 }
992 safetyCheck();
993
994 {
995 // delete triggered by parent
996 QObject *obj, *parent;
997 parent = new QObject;
998 obj = new QObject(parent);
999 QWeakPointer<QObject> weak(obj);
1000
1001 // now delete the parent
1002 delete parent;
1003 QVERIFY(weak.isNull());
1004 }
1005 safetyCheck();
1006
1007 {
1008 // same as above, but set the parent after QWeakPointer is created
1009 QObject *obj, *parent;
1010 obj = new QObject;
1011 QWeakPointer<QObject> weak(obj);
1012
1013 parent = new QObject;
1014 obj->setParent(parent);
1015
1016 // now delete the parent
1017 delete parent;
1018 QVERIFY(weak.isNull());
1019 }
1020 safetyCheck();
1021
1022 {
1023 // with two QWeakPointers
1024 QObject *obj = new QObject;
1025 QWeakPointer<QObject> weak(obj);
1026
1027 {
1028 QWeakPointer<QObject> weak2(obj);
1029 QVERIFY(!weak2.isNull());
1030 QVERIFY(weak == weak2);
1031 }
1032 QVERIFY(!weak.isNull());
1033
1034 delete obj;
1035 QVERIFY(weak.isNull());
1036 }
1037 safetyCheck();
1038
1039 {
1040 // same, but delete the pointer while two QWeakPointers exist
1041 QObject *obj = new QObject;
1042 QWeakPointer<QObject> weak(obj);
1043
1044 {
1045 QWeakPointer<QObject> weak2(obj);
1046 QVERIFY(!weak2.isNull());
1047
1048 delete obj;
1049 QVERIFY(weak.isNull());
1050 QVERIFY(weak2.isNull());
1051 }
1052 QVERIFY(weak.isNull());
1053 }
1054 safetyCheck();
1055#endif
1056}
1057
1058#if QT_DEPRECATED_SINCE(5, 0)
1059void tst_QSharedPointer::noSharedPointerFromWeakQObject()
1060{
1061 // you're not allowed to create a QSharedPointer from an unmanaged QObject
1062 QObject obj;
1063 QWeakPointer<QObject> weak(&obj);
1064
1065 {
1066 QTest::ignoreMessage(type: QtWarningMsg , message: "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
1067 QSharedPointer<QObject> strong = weak.toStrongRef();
1068 QVERIFY(strong.isNull());
1069 }
1070 {
1071 QTest::ignoreMessage(type: QtWarningMsg , message: "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
1072 QSharedPointer<QObject> strong = weak;
1073 QVERIFY(strong.isNull());
1074 }
1075
1076 QCOMPARE(weak.data(), &obj);
1077 // if something went wrong, we'll probably crash here
1078}
1079
1080void tst_QSharedPointer::sharedPointerFromQObjectWithWeak()
1081{
1082 QObject *ptr = new QObject;
1083 QWeakPointer<QObject> weak = ptr;
1084 {
1085 QSharedPointer<QObject> shared(ptr);
1086 QVERIFY(!weak.isNull());
1087 QCOMPARE(shared.data(), ptr);
1088 QCOMPARE(weak.data(), ptr);
1089 }
1090 QVERIFY(weak.isNull());
1091}
1092#endif
1093
1094void tst_QSharedPointer::weakQObjectFromSharedPointer()
1095{
1096#if QT_DEPRECATED_SINCE(5, 0)
1097 {
1098 // this is the inverse of the above: you're allowed to create a QWeakPointer
1099 // from a managed QObject
1100 QSharedPointer<QObject> shared(new QObject);
1101 QWeakPointer<QObject> weak = shared.data();
1102 QVERIFY(!weak.isNull());
1103
1104 // delete:
1105 shared.clear();
1106 QVERIFY(weak.isNull());
1107 }
1108#endif
1109 {
1110 QSharedPointer<QObject> shared(new QObject);
1111 QWeakPointer<QObject> weak = shared;
1112 QVERIFY(!weak.isNull());
1113
1114 // delete:
1115 shared.clear();
1116 QVERIFY(weak.isNull());
1117 }
1118}
1119
1120void tst_QSharedPointer::objectCast()
1121{
1122 {
1123 OtherObject *data = new OtherObject;
1124 QSharedPointer<QObject> baseptr = QSharedPointer<QObject>(data);
1125 QVERIFY(baseptr == data);
1126 QVERIFY(data == baseptr);
1127
1128 // perform object cast
1129 QSharedPointer<OtherObject> ptr = qSharedPointerObjectCast<OtherObject>(src: baseptr);
1130 QVERIFY(!ptr.isNull());
1131 QCOMPARE(ptr.data(), data);
1132 QVERIFY(ptr == data);
1133
1134 // again:
1135 ptr = baseptr.objectCast<OtherObject>();
1136 QVERIFY(ptr == data);
1137
1138 // again:
1139 ptr = qobject_cast<OtherObject *>(src: baseptr);
1140 QVERIFY(ptr == data);
1141
1142 // again:
1143 ptr = qobject_cast<QSharedPointer<OtherObject> >(src: baseptr);
1144 QVERIFY(ptr == data);
1145 }
1146 safetyCheck();
1147
1148 {
1149 const OtherObject *data = new OtherObject;
1150 QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(data);
1151 QVERIFY(baseptr == data);
1152 QVERIFY(data == baseptr);
1153
1154 // perform object cast
1155 QSharedPointer<const OtherObject> ptr = qSharedPointerObjectCast<const OtherObject>(src: baseptr);
1156 QVERIFY(!ptr.isNull());
1157 QCOMPARE(ptr.data(), data);
1158 QVERIFY(ptr == data);
1159
1160 // again:
1161 ptr = baseptr.objectCast<const OtherObject>();
1162 QVERIFY(ptr == data);
1163
1164 // again:
1165 ptr = qobject_cast<const OtherObject *>(src: baseptr);
1166 QVERIFY(ptr == data);
1167
1168 // again:
1169 ptr = qobject_cast<QSharedPointer<const OtherObject> >(src: baseptr);
1170 QVERIFY(ptr == data);
1171 }
1172 safetyCheck();
1173
1174 {
1175 OtherObject *data = new OtherObject;
1176 QSharedPointer<OtherObject> ptr = QSharedPointer<OtherObject>(data);
1177 QWeakPointer<QObject> weakptr = ptr;
1178
1179 {
1180 // perform object cast
1181 QSharedPointer<OtherObject> otherptr = qSharedPointerObjectCast<OtherObject>(src: weakptr);
1182 QVERIFY(otherptr == ptr);
1183
1184 // again:
1185 otherptr = qobject_cast<OtherObject *>(src: weakptr);
1186 QVERIFY(otherptr == ptr);
1187
1188 // again:
1189 otherptr = qobject_cast<QSharedPointer<OtherObject> >(src: weakptr);
1190 QVERIFY(otherptr == ptr);
1191 }
1192
1193 // drop the reference:
1194 ptr.clear();
1195 QVERIFY(ptr.isNull());
1196 QVERIFY(weakptr.toStrongRef().isNull());
1197 QVERIFY(weakptr.lock().isNull());
1198
1199 // verify that the object casts fail without crash
1200 QSharedPointer<OtherObject> otherptr = qSharedPointerObjectCast<OtherObject>(src: weakptr);
1201 QVERIFY(otherptr.isNull());
1202
1203 // again:
1204 otherptr = qobject_cast<OtherObject *>(src: weakptr);
1205 QVERIFY(otherptr.isNull());
1206
1207 // again:
1208 otherptr = qobject_cast<QSharedPointer<OtherObject> >(src: weakptr);
1209 QVERIFY(otherptr.isNull());
1210 }
1211 safetyCheck();
1212}
1213
1214
1215void tst_QSharedPointer::objectCastStdSharedPtr()
1216{
1217 {
1218 OtherObject *data = new OtherObject;
1219 std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data);
1220 QVERIFY(baseptr.get() == data);
1221
1222 // perform successful object cast
1223 std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(src: baseptr);
1224 QVERIFY(ptr.get());
1225 QVERIFY(ptr.get() == data);
1226
1227 QVERIFY(baseptr.get() == data);
1228 }
1229
1230 {
1231 OtherObject *data = new OtherObject;
1232 std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data);
1233 QVERIFY(baseptr.get() == data);
1234
1235 // perform successful object cast
1236 std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(src: std::move(baseptr));
1237 QVERIFY(ptr.get());
1238 QVERIFY(ptr.get() == data);
1239
1240 QVERIFY(!baseptr.get());
1241 }
1242
1243 {
1244 QObject *data = new QObject;
1245 std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data);
1246 QVERIFY(baseptr.get() == data);
1247
1248 // perform unsuccessful object cast
1249 std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(src: baseptr);
1250 QVERIFY(!ptr.get());
1251
1252 QVERIFY(baseptr.get() == data);
1253 }
1254
1255 {
1256 QObject *data = new QObject;
1257 std::shared_ptr<QObject> baseptr = std::shared_ptr<QObject>(data);
1258 QVERIFY(baseptr.get() == data);
1259
1260 // perform unsuccessful object cast
1261 std::shared_ptr<OtherObject> ptr = qobject_pointer_cast<OtherObject>(src: std::move(baseptr));
1262 QVERIFY(!ptr.get());
1263
1264 QVERIFY(baseptr.get() == data);
1265 }
1266}
1267
1268void tst_QSharedPointer::differentPointers()
1269{
1270 {
1271 DiffPtrDerivedData *aData = new DiffPtrDerivedData;
1272 Data *aBase = aData;
1273
1274 // ensure that this compiler isn't broken
1275 if (*reinterpret_cast<quintptr *>(&aData) == *reinterpret_cast<quintptr *>(&aBase))
1276 QFAIL("Something went very wrong -- we couldn't create two different pointers to the same object");
1277 if (aData != aBase || aBase != aData)
1278 QSKIP("Broken compiler");
1279
1280 QSharedPointer<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData);
1281 QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(src: ptr);
1282 qDebug(msg: "naked: orig: %p; base: %p (%s) -- QSharedPointer: orig: %p; base %p (%s) -- result: %s",
1283 aData, aBase, aData == aBase ? "equal" : "not equal",
1284 ptr.data(), baseptr.data(), ptr.data() == baseptr.data() ? "equal" : "not equal",
1285 baseptr.data() == aData ? "equal" : "not equal");
1286
1287 QVERIFY(ptr.data() == baseptr.data());
1288 QVERIFY(baseptr.data() == ptr.data());
1289 QVERIFY(ptr == baseptr);
1290 QVERIFY(baseptr == ptr);
1291
1292 QVERIFY(ptr.data() == aBase);
1293 QVERIFY(aBase == ptr.data());
1294 QVERIFY(ptr.data() == aData);
1295 QVERIFY(aData == ptr.data());
1296
1297 QVERIFY(ptr == aBase);
1298 QVERIFY(aBase == ptr);
1299 QVERIFY(ptr == aData);
1300 QVERIFY(aData == ptr);
1301
1302 QVERIFY(baseptr.data() == aBase);
1303 QVERIFY(aBase == baseptr.data());
1304 QVERIFY(baseptr == aBase);
1305 QVERIFY(aBase == baseptr);
1306
1307 QVERIFY(baseptr.data() == aData);
1308 QVERIFY(aData == baseptr.data());
1309 QVERIFY(baseptr == aData);
1310 QVERIFY(aData == baseptr);
1311 }
1312 safetyCheck();
1313
1314 {
1315 DiffPtrDerivedData *aData = new DiffPtrDerivedData;
1316 Data *aBase = aData;
1317 QVERIFY(aData == aBase);
1318 QVERIFY(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
1319
1320 QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
1321 QSharedPointer<DiffPtrDerivedData> ptr = qSharedPointerCast<DiffPtrDerivedData>(src: baseptr);
1322 QVERIFY(ptr == baseptr);
1323 QVERIFY(ptr.data() == baseptr.data());
1324 QVERIFY(ptr == aBase);
1325 QVERIFY(baseptr == aData);
1326 }
1327 safetyCheck();
1328
1329 {
1330 DiffPtrDerivedData *aData = new DiffPtrDerivedData;
1331 Data *aBase = aData;
1332 QVERIFY(aData == aBase);
1333 QVERIFY(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
1334
1335 QSharedPointer<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData);
1336 QSharedPointer<Data> baseptr = ptr;
1337 QVERIFY(ptr == baseptr);
1338 QVERIFY(ptr.data() == baseptr.data());
1339 QVERIFY(ptr == aBase);
1340 QVERIFY(ptr == aData);
1341 QVERIFY(baseptr == aData);
1342 QVERIFY(baseptr == aBase);
1343 }
1344 safetyCheck();
1345}
1346
1347void tst_QSharedPointer::virtualBaseDifferentPointers()
1348{
1349 {
1350 VirtualDerived *aData = new VirtualDerived;
1351 Data *aBase = aData;
1352 QVERIFY(aData == aBase);
1353 QVERIFY(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
1354
1355 QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
1356 QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(src: ptr);
1357 QVERIFY(ptr == baseptr);
1358 QVERIFY(ptr.data() == baseptr.data());
1359 QVERIFY(ptr == aBase);
1360 QVERIFY(ptr == aData);
1361 QVERIFY(baseptr == aData);
1362 QVERIFY(baseptr == aBase);
1363 }
1364 safetyCheck();
1365
1366 {
1367 VirtualDerived *aData = new VirtualDerived;
1368 Data *aBase = aData;
1369 QVERIFY(aData == aBase);
1370 QVERIFY(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
1371
1372 QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
1373 QSharedPointer<Data> baseptr = ptr;
1374 QVERIFY(ptr == baseptr);
1375 QVERIFY(ptr.data() == baseptr.data());
1376 QVERIFY(ptr == aBase);
1377 QVERIFY(ptr == aData);
1378 QVERIFY(baseptr == aData);
1379 QVERIFY(baseptr == aBase);
1380 }
1381 safetyCheck();
1382}
1383
1384#ifndef QTEST_NO_RTTI
1385void tst_QSharedPointer::dynamicCast()
1386{
1387 DerivedData *aData = new DerivedData;
1388 QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
1389
1390 {
1391 QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(src: baseptr);
1392 QVERIFY(baseptr == derivedptr);
1393 QCOMPARE(derivedptr.data(), aData);
1394 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1395 }
1396 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1397 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1398
1399 {
1400 QWeakPointer<Data> weakptr = baseptr;
1401 QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(src: weakptr);
1402 QVERIFY(baseptr == derivedptr);
1403 QCOMPARE(derivedptr.data(), aData);
1404 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1405 }
1406 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1407 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1408
1409 {
1410 QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>();
1411 QVERIFY(baseptr == derivedptr);
1412 QCOMPARE(derivedptr.data(), aData);
1413 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1414 }
1415 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1416 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1417}
1418
1419void tst_QSharedPointer::dynamicCastDifferentPointers()
1420{
1421 // DiffPtrDerivedData derives from both Data and Stuffing
1422 DiffPtrDerivedData *aData = new DiffPtrDerivedData;
1423 QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
1424
1425 {
1426 QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(src: baseptr);
1427 QVERIFY(baseptr == derivedptr);
1428 QCOMPARE(derivedptr.data(), aData);
1429 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1430 }
1431 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1432 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1433
1434 {
1435 QWeakPointer<Data> weakptr = baseptr;
1436 QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(src: weakptr);
1437 QVERIFY(baseptr == derivedptr);
1438 QCOMPARE(derivedptr.data(), aData);
1439 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1440 }
1441 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1442 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1443
1444 {
1445 QSharedPointer<DiffPtrDerivedData> derivedptr = baseptr.dynamicCast<DiffPtrDerivedData>();
1446 QVERIFY(baseptr == derivedptr);
1447 QCOMPARE(derivedptr.data(), aData);
1448 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1449 }
1450 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1451 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1452
1453 {
1454 Stuffing *nakedptr = dynamic_cast<Stuffing *>(baseptr.data());
1455 QVERIFY(nakedptr);
1456
1457 QSharedPointer<Stuffing> otherbaseptr = qSharedPointerDynamicCast<Stuffing>(src: baseptr);
1458 QVERIFY(!otherbaseptr.isNull());
1459 QVERIFY(otherbaseptr == nakedptr);
1460 QCOMPARE(otherbaseptr.data(), nakedptr);
1461 QCOMPARE(static_cast<DiffPtrDerivedData*>(otherbaseptr.data()), aData);
1462 }
1463}
1464
1465void tst_QSharedPointer::dynamicCastVirtualBase()
1466{
1467 VirtualDerived *aData = new VirtualDerived;
1468 QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
1469
1470 {
1471 QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(src: baseptr);
1472 QVERIFY(baseptr == derivedptr);
1473 QCOMPARE(derivedptr.data(), aData);
1474 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1475 }
1476 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1477 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1478
1479 {
1480 QWeakPointer<Data> weakptr = baseptr;
1481 QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(src: weakptr);
1482 QVERIFY(baseptr == derivedptr);
1483 QCOMPARE(derivedptr.data(), aData);
1484 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1485 }
1486 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1487 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1488
1489 {
1490 QSharedPointer<VirtualDerived> derivedptr = baseptr.dynamicCast<VirtualDerived>();
1491 QVERIFY(baseptr == derivedptr);
1492 QCOMPARE(derivedptr.data(), aData);
1493 QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
1494 }
1495 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1496 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1497}
1498
1499void tst_QSharedPointer::dynamicCastFailure()
1500{
1501 QSharedPointer<Data> baseptr = QSharedPointer<Data>(new Data);
1502 QVERIFY(dynamic_cast<DerivedData *>(baseptr.data()) == 0);
1503
1504 {
1505 QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(src: baseptr);
1506 QVERIFY(derivedptr.isNull());
1507 }
1508 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1509 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1510
1511 {
1512 QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>();
1513 QVERIFY(derivedptr.isNull());
1514 }
1515 QCOMPARE(int(refCountData(baseptr)->weakref.loadRelaxed()), 1);
1516 QCOMPARE(int(refCountData(baseptr)->strongref.loadRelaxed()), 1);
1517}
1518
1519void tst_QSharedPointer::dynamicCastFailureNoLeak()
1520{
1521 NonTracked::dynamicCastFailureNoLeak();
1522}
1523#endif
1524
1525void tst_QSharedPointer::constCorrectness()
1526{
1527 {
1528 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data);
1529 QSharedPointer<const Data> cptr(ptr);
1530 QSharedPointer<volatile Data> vptr(ptr);
1531 cptr = ptr;
1532 vptr = ptr;
1533
1534 ptr = qSharedPointerConstCast<Data>(src: cptr);
1535 ptr = qSharedPointerConstCast<Data>(src: vptr);
1536 ptr = cptr.constCast<Data>();
1537 ptr = vptr.constCast<Data>();
1538
1539 QSharedPointer<const volatile Data> cvptr(ptr);
1540 QSharedPointer<const volatile Data> cvptr2(cptr);
1541 QSharedPointer<const volatile Data> cvptr3(vptr);
1542 cvptr = ptr;
1543 cvptr2 = cptr;
1544 cvptr3 = vptr;
1545 ptr = qSharedPointerConstCast<Data>(src: cvptr);
1546 ptr = cvptr.constCast<Data>();
1547 }
1548 safetyCheck();
1549
1550 {
1551 Data *aData = new Data;
1552 QSharedPointer<Data> ptr = QSharedPointer<Data>(aData);
1553 const QSharedPointer<Data> cptr = ptr;
1554
1555 ptr = cptr;
1556 QSharedPointer<Data> other = qSharedPointerCast<Data>(src: cptr);
1557
1558#ifndef QT_NO_DYNAMIC_CAST
1559 other = qSharedPointerDynamicCast<Data>(src: cptr);
1560#endif
1561
1562 QCOMPARE(cptr.data(), aData);
1563 QCOMPARE(cptr.operator->(), aData);
1564 }
1565 safetyCheck();
1566}
1567
1568static int customDeleterFnCallCount;
1569void customDeleterFn(Data *ptr)
1570{
1571 ++customDeleterFnCallCount;
1572 delete ptr;
1573}
1574
1575static int refcount;
1576
1577template <typename T>
1578struct CustomDeleter
1579{
1580 CustomDeleter() { ++refcount; }
1581 CustomDeleter(const CustomDeleter &) { ++refcount; }
1582 ~CustomDeleter() { --refcount; }
1583 inline void operator()(T *ptr)
1584 {
1585 delete ptr;
1586 ++callCount;
1587 }
1588 static int callCount;
1589};
1590template<typename T> int CustomDeleter<T>::callCount = 0;
1591
1592void tst_QSharedPointer::customDeleter()
1593{
1594 {
1595 QSharedPointer<Data> ptr(0, &Data::doDelete);
1596 QSharedPointer<Data> ptr2(0, &Data::alsoDelete);
1597 QSharedPointer<Data> ptr3(0, &Data::virtualDelete);
1598 }
1599 safetyCheck();
1600 {
1601 QSharedPointer<Data> ptr(nullptr, &Data::doDelete);
1602 QSharedPointer<Data> ptr2(nullptr, &Data::alsoDelete);
1603 QSharedPointer<Data> ptr3(nullptr, &Data::virtualDelete);
1604 }
1605 safetyCheck();
1606 {
1607 QSharedPointer<Data> ptr(new Data, &Data::doDelete);
1608 QSharedPointer<Data> ptr2(new Data, &Data::alsoDelete);
1609 QSharedPointer<Data> ptr3(new Data, &Data::virtualDelete);
1610 }
1611 safetyCheck();
1612 {
1613 QSharedPointer<DerivedData> ptr(new DerivedData, &Data::doDelete);
1614 QSharedPointer<DerivedData> ptr2(new DerivedData, &Data::alsoDelete);
1615 QSharedPointer<DerivedData> ptr3(new DerivedData, &Data::virtualDelete);
1616 }
1617 safetyCheck();
1618
1619 customDeleterFnCallCount = 0;
1620 {
1621 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
1622 ptr.data();
1623 QCOMPARE(customDeleterFnCallCount, 0);
1624 }
1625 QCOMPARE(customDeleterFnCallCount, 1);
1626 safetyCheck();
1627
1628 customDeleterFnCallCount = 0;
1629 {
1630 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
1631 QCOMPARE(customDeleterFnCallCount, 0);
1632 ptr.clear();
1633 QCOMPARE(customDeleterFnCallCount, 1);
1634 }
1635 QCOMPARE(customDeleterFnCallCount, 1);
1636 safetyCheck();
1637
1638 customDeleterFnCallCount = 0;
1639 {
1640 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
1641 QCOMPARE(customDeleterFnCallCount, 0);
1642 ptr = QSharedPointer<Data>(new Data);
1643 QCOMPARE(customDeleterFnCallCount, 1);
1644 }
1645 QCOMPARE(customDeleterFnCallCount, 1);
1646 safetyCheck();
1647
1648 customDeleterFnCallCount = 0;
1649 {
1650 QSharedPointer<Data> ptr = QSharedPointer<Data>(new DerivedData, customDeleterFn);
1651 ptr.data();
1652 QCOMPARE(customDeleterFnCallCount, 0);
1653 }
1654 QCOMPARE(customDeleterFnCallCount, 1);
1655 safetyCheck();
1656
1657 customDeleterFnCallCount = 0;
1658 {
1659 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, customDeleterFn);
1660 ptr.data();
1661 QCOMPARE(customDeleterFnCallCount, 0);
1662 }
1663 QCOMPARE(customDeleterFnCallCount, 1);
1664 safetyCheck();
1665
1666 customDeleterFnCallCount = 0;
1667 {
1668 QSharedPointer<Data> other;
1669 {
1670 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, customDeleterFn);
1671 other = ptr;
1672 QCOMPARE(customDeleterFnCallCount, 0);
1673 }
1674 QCOMPARE(customDeleterFnCallCount, 0);
1675 }
1676 QCOMPARE(customDeleterFnCallCount, 1);
1677 safetyCheck();
1678
1679 customDeleterFnCallCount = 0;
1680 {
1681 QSharedPointer<Data> other;
1682 {
1683 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, customDeleterFn);
1684 other = ptr;
1685 QCOMPARE(customDeleterFnCallCount, 0);
1686 }
1687 QCOMPARE(customDeleterFnCallCount, 0);
1688 }
1689 QCOMPARE(customDeleterFnCallCount, 1);
1690 safetyCheck();
1691
1692 refcount = 0;
1693 CustomDeleter<Data> dataDeleter;
1694 dataDeleter.callCount = 0;
1695 {
1696 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, dataDeleter);
1697 ptr.data();
1698 QCOMPARE(dataDeleter.callCount, 0);
1699 }
1700 QCOMPARE(dataDeleter.callCount, 1);
1701 QCOMPARE(refcount, 1);
1702 safetyCheck();
1703
1704 dataDeleter.callCount = 0;
1705 {
1706 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, dataDeleter);
1707 QSharedPointer<Data> other = ptr;
1708 other.clear();
1709 QCOMPARE(dataDeleter.callCount, 0);
1710 }
1711 QCOMPARE(dataDeleter.callCount, 1);
1712 QCOMPARE(refcount, 1);
1713 safetyCheck();
1714
1715 dataDeleter.callCount = 0;
1716 {
1717 QSharedPointer<Data> other;
1718 {
1719 QSharedPointer<Data> ptr = QSharedPointer<Data>(new Data, dataDeleter);
1720 other = ptr;
1721 QCOMPARE(dataDeleter.callCount, 0);
1722 }
1723 QCOMPARE(dataDeleter.callCount, 0);
1724 }
1725 QCOMPARE(dataDeleter.callCount, 1);
1726 QCOMPARE(refcount, 1);
1727 safetyCheck();
1728
1729 dataDeleter.callCount = 0;
1730 {
1731 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, dataDeleter);
1732 ptr.data();
1733 QCOMPARE(dataDeleter.callCount, 0);
1734 }
1735 QCOMPARE(dataDeleter.callCount, 1);
1736 QCOMPARE(refcount, 1);
1737 safetyCheck();
1738
1739 CustomDeleter<DerivedData> derivedDataDeleter;
1740 derivedDataDeleter.callCount = 0;
1741 dataDeleter.callCount = 0;
1742 {
1743 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, derivedDataDeleter);
1744 ptr.data();
1745 QCOMPARE(dataDeleter.callCount, 0);
1746 QCOMPARE(derivedDataDeleter.callCount, 0);
1747 }
1748 QCOMPARE(dataDeleter.callCount, 0);
1749 QCOMPARE(derivedDataDeleter.callCount, 1);
1750 QCOMPARE(refcount, 2);
1751 safetyCheck();
1752
1753 derivedDataDeleter.callCount = 0;
1754 dataDeleter.callCount = 0;
1755 {
1756 QSharedPointer<Data> other;
1757 {
1758 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, dataDeleter);
1759 other = ptr;
1760 QCOMPARE(dataDeleter.callCount, 0);
1761 QCOMPARE(derivedDataDeleter.callCount, 0);
1762 }
1763 QCOMPARE(dataDeleter.callCount, 0);
1764 QCOMPARE(derivedDataDeleter.callCount, 0);
1765 }
1766 QCOMPARE(dataDeleter.callCount, 1);
1767 QCOMPARE(derivedDataDeleter.callCount, 0);
1768 QCOMPARE(refcount, 2);
1769 safetyCheck();
1770
1771 derivedDataDeleter.callCount = 0;
1772 dataDeleter.callCount = 0;
1773 {
1774 QSharedPointer<Data> other;
1775 {
1776 QSharedPointer<DerivedData> ptr = QSharedPointer<DerivedData>(new DerivedData, derivedDataDeleter);
1777 other = ptr;
1778 QCOMPARE(dataDeleter.callCount, 0);
1779 QCOMPARE(derivedDataDeleter.callCount, 0);
1780 }
1781 QCOMPARE(dataDeleter.callCount, 0);
1782 QCOMPARE(derivedDataDeleter.callCount, 0);
1783 }
1784 QCOMPARE(dataDeleter.callCount, 0);
1785 QCOMPARE(derivedDataDeleter.callCount, 1);
1786 QCOMPARE(refcount, 2);
1787 safetyCheck();
1788
1789 CustomDeleter<NVDData> nvdeleter;
1790 nvdeleter.callCount = 0;
1791 {
1792 QSharedPointer<NVDData> ptr(new NVDData, nvdeleter);
1793 }
1794 QCOMPARE(nvdeleter.callCount, 1);
1795 safetyCheck();
1796
1797 CustomDeleter<NVDDerivedData> nvderiveddeleter;
1798 nvdeleter.callCount = 0;
1799 nvderiveddeleter.callCount = 0;
1800 {
1801 QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData, nvderiveddeleter);
1802 }
1803 QCOMPARE(nvdeleter.callCount, 0);
1804 QCOMPARE(nvderiveddeleter.callCount, 1);
1805 safetyCheck();
1806
1807 nvdeleter.callCount = 0;
1808 nvderiveddeleter.callCount = 0;
1809 {
1810 QSharedPointer<NVDData> ptr(new NVDDerivedData, nvderiveddeleter);
1811 }
1812 QCOMPARE(nvdeleter.callCount, 0);
1813 QCOMPARE(nvderiveddeleter.callCount, 1);
1814 safetyCheck();
1815
1816 // a custom deleter with a different pointer parameter
1817 {
1818 QSharedPointer<char> ptr(static_cast<char *>(malloc(size: 1)), free);
1819 }
1820 safetyCheck();
1821}
1822
1823// The compiler needs to be in C++11 mode and to support lambdas
1824void tst_QSharedPointer::lambdaCustomDeleter()
1825{
1826 {
1827 // stateless, one-argument
1828 QSharedPointer<Data> ptr(new Data, [](Data *d) { delete d; });
1829 QSharedPointer<Data> ptr2(new Data, [](Data *d) { d->doDelete(); });
1830 }
1831 safetyCheck();
1832
1833 customDeleterFnCallCount = 0;
1834 {
1835 // stateless, one-argument, modifies globals
1836 QSharedPointer<Data> ptr(new Data, [](Data *d) { ++customDeleterFnCallCount; delete d; });
1837 }
1838 safetyCheck();
1839 QCOMPARE(customDeleterFnCallCount, 1);
1840
1841 {
1842 // stateful by ref, one-argument
1843 int i = 0;
1844 QSharedPointer<Data> ptr(new Data, [&i](Data *d) { i = 42; delete d; });
1845 ptr.clear();
1846 QCOMPARE(i, 42);
1847 }
1848 safetyCheck();
1849}
1850
1851void tst_QSharedPointer::customDeleterOnNullptr()
1852{
1853 Data *null = nullptr;
1854 int callCount = 0;
1855 auto deleter = [&callCount](Data *) { ++callCount; };
1856 {
1857 QSharedPointer<Data> ptr(null, deleter);
1858 }
1859 safetyCheck();
1860 QCOMPARE(callCount, 1);
1861
1862 callCount = 0;
1863 {
1864 QSharedPointer<Data> ptr(nullptr, deleter);
1865 }
1866 safetyCheck();
1867 QCOMPARE(callCount, 1);
1868
1869 callCount = 0;
1870 {
1871 QSharedPointer<Data> ptr1(null, deleter);
1872 QSharedPointer<Data> ptr2(nullptr, deleter);
1873 }
1874 safetyCheck();
1875 QCOMPARE(callCount, 2);
1876}
1877
1878void customQObjectDeleterFn(QObject *obj)
1879{
1880 ++customDeleterFnCallCount;
1881 delete obj;
1882}
1883
1884void tst_QSharedPointer::creating()
1885{
1886 Data::generationCounter = Data::destructorCounter = 0;
1887 {
1888 QSharedPointer<Data> ptr = QSharedPointer<Data>::create();
1889 QVERIFY(ptr.data());
1890 QCOMPARE(Data::generationCounter, 1);
1891 QCOMPARE(ptr->generation, 1);
1892 QCOMPARE(Data::destructorCounter, 0);
1893
1894 QCOMPARE(ptr->classLevel(), 1);
1895
1896 ptr.clear();
1897 QCOMPARE(Data::destructorCounter, 1);
1898 }
1899 safetyCheck();
1900
1901 Data::generationCounter = Data::destructorCounter = 0;
1902 {
1903 QSharedPointer<Data> ptr = QSharedPointer<Data>::create();
1904 QWeakPointer<Data> weakptr = ptr;
1905 QtSharedPointer::ExternalRefCountData *d = refCountData(b: ptr);
1906
1907 ptr.clear();
1908 QVERIFY(ptr.isNull());
1909 QCOMPARE(Data::destructorCounter, 1);
1910
1911 // valgrind will complain here if something happened to the pointer
1912 QVERIFY(d->weakref.loadRelaxed() == 1);
1913 QVERIFY(d->strongref.loadRelaxed() == 0);
1914 }
1915 safetyCheck();
1916
1917 Data::generationCounter = Data::destructorCounter = 0;
1918 DerivedData::derivedDestructorCounter = 0;
1919 {
1920 QSharedPointer<Data> ptr = QSharedPointer<DerivedData>::create();
1921 QCOMPARE(ptr->classLevel(), 2);
1922 QCOMPARE(ptr.staticCast<DerivedData>()->moreData, 0);
1923 ptr.clear();
1924
1925 QCOMPARE(Data::destructorCounter, 1);
1926 QCOMPARE(DerivedData::derivedDestructorCounter, 1);
1927 }
1928 safetyCheck();
1929
1930 {
1931 QSharedPointer<Data> ptr = QSharedPointer<DiffPtrDerivedData>::create();
1932 QCOMPARE(ptr->classLevel(), 3);
1933 QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[7]+0, 16-7);
1934 QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[3]+0, 16-3);
1935 QCOMPARE(ptr.staticCast<DiffPtrDerivedData>()->buffer[0]+0, 16);
1936 }
1937 safetyCheck();
1938
1939 {
1940 QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>::create();
1941 QCOMPARE(ptr->classLevel(), 4);
1942 QCOMPARE(ptr->moreData, 0xc0ffee);
1943
1944 QSharedPointer<Data> baseptr = ptr;
1945 QCOMPARE(baseptr->classLevel(), 4);
1946 }
1947 safetyCheck();
1948}
1949
1950void tst_QSharedPointer::creatingCvQualified()
1951{
1952 auto cptr = QSharedPointer<const Data>::create();
1953 auto vptr = QSharedPointer<volatile Data>::create();
1954 auto cvptr = QSharedPointer<const volatile Data>::create();
1955}
1956
1957void tst_QSharedPointer::creatingVariadic()
1958{
1959 int i = 42;
1960
1961 {
1962 NoDefaultConstructor1(1); // control check
1963 QSharedPointer<NoDefaultConstructor1> ptr = QSharedPointer<NoDefaultConstructor1>::create(arguments: 1);
1964 QCOMPARE(ptr->i, 1);
1965
1966 NoDefaultConstructor1(0u); // control check
1967 ptr = QSharedPointer<NoDefaultConstructor1>::create(arguments: 0u);
1968 QCOMPARE(ptr->i, 42);
1969
1970 NoDefaultConstructor1 x(i); // control check
1971 ptr = QSharedPointer<NoDefaultConstructor1>::create(arguments&: i);
1972 QCOMPARE(ptr->i, i);
1973 }
1974 {
1975 NoDefaultConstructor2((void*)0, 1); // control check
1976 QSharedPointer<NoDefaultConstructor2> ptr = QSharedPointer<NoDefaultConstructor2>::create(arguments: (void*)0, arguments: 1);
1977 QCOMPARE(ptr->i, 1);
1978 QCOMPARE(ptr->ptr, (void*)0);
1979
1980 int *null = 0;
1981 NoDefaultConstructor2(null, 2); // control check
1982 ptr = QSharedPointer<NoDefaultConstructor2>::create(arguments&: null, arguments: 2);
1983 QCOMPARE(ptr->i, 2);
1984 QCOMPARE(ptr->ptr, (void*)0);
1985
1986 NoDefaultConstructor2(nullptr, 3); // control check
1987 ptr = QSharedPointer<NoDefaultConstructor2>::create(arguments: nullptr, arguments: 3);
1988 QCOMPARE(ptr->i, 3);
1989 QCOMPARE(ptr->ptr, (void*)nullptr);
1990 }
1991 {
1992 NoDefaultConstructorRef1 x(i); // control check
1993 QSharedPointer<NoDefaultConstructorRef1> ptr = QSharedPointer<NoDefaultConstructorRef1>::create(arguments&: i);
1994 QCOMPARE(ptr->i, i);
1995 QCOMPARE(&ptr->i, &i);
1996 }
1997 {
1998 NoDefaultConstructorRRef1(std::move(i)); // control check
1999 QSharedPointer<NoDefaultConstructorRRef1> ptr = QSharedPointer<NoDefaultConstructorRRef1>::create(arguments: std::move(i));
2000 QCOMPARE(ptr->i, i);
2001 }
2002 {
2003 NoDefaultConstructorRRef2(std::unique_ptr<int>(new int(1))); // control check
2004 QSharedPointer<NoDefaultConstructorRRef2> ptr = QSharedPointer<NoDefaultConstructorRRef2>::create(arguments: std::unique_ptr<int>(new int(1)));
2005 QCOMPARE(*ptr->i, 1);
2006
2007 std::unique_ptr<int> p(new int(i));
2008 ptr = QSharedPointer<NoDefaultConstructorRRef2>::create(arguments: std::move(p));
2009 QCOMPARE(*ptr->i, i);
2010 }
2011 {
2012 QString text("Hello, World");
2013 NoDefaultConstructorRef2(text, 1); // control check
2014 QSharedPointer<NoDefaultConstructorRef2> ptr = QSharedPointer<NoDefaultConstructorRef2>::create(arguments&: text, arguments: 1);
2015 QCOMPARE(ptr->str, text);
2016 QCOMPARE(ptr->i, 1);
2017 }
2018 {
2019 QSharedPointer<NoDefaultConstructorConstRef2> ptr;
2020 NoDefaultConstructorConstRef2(QLatin1String("string"), 1); // control check
2021 ptr = QSharedPointer<NoDefaultConstructorConstRef2>::create(arguments: QLatin1String("string"), arguments: 1);
2022 QCOMPARE(ptr->str, QString("string"));
2023 QCOMPARE(ptr->i, 1);
2024
2025 NoDefaultConstructorConstRef2(QByteArray("bytearray")); // control check
2026 ptr = QSharedPointer<NoDefaultConstructorConstRef2>::create(arguments: QByteArray("bytearray"));
2027 QCOMPARE(ptr->str, QString("bytearray"));
2028 QCOMPARE(ptr->i, 42);
2029 }
2030}
2031
2032void tst_QSharedPointer::creatingQObject()
2033{
2034 {
2035 QSharedPointer<QObject> ptr = QSharedPointer<QObject>::create();
2036 QCOMPARE(ptr->metaObject(), &QObject::staticMetaObject);
2037
2038 QPointer<QObject> qptr = ptr.data();
2039 ptr.clear();
2040
2041 QVERIFY(qptr.isNull());
2042 }
2043 safetyCheck();
2044
2045 {
2046 QSharedPointer<QObject> ptr = QSharedPointer<OtherObject>::create();
2047 QCOMPARE(ptr->metaObject(), &OtherObject::staticMetaObject);
2048 }
2049 safetyCheck();
2050}
2051
2052void tst_QSharedPointer::mixTrackingPointerCode()
2053{
2054 {
2055 // pointer created with tracking
2056 // deleted in code without tracking
2057 QSharedPointer<int> ptr = QSharedPointer<int>(new int(42));
2058 Wrapper w(ptr);
2059 ptr.clear();
2060 }
2061 safetyCheck();
2062
2063 {
2064 // pointer created without tracking
2065 // deleted in code with tracking
2066 Wrapper w = Wrapper::create();
2067 w.ptr.clear();
2068 }
2069}
2070
2071class ThreadData
2072{
2073 QAtomicInt * volatile ptr;
2074public:
2075 ThreadData(QAtomicInt *p) : ptr(p) { }
2076 ~ThreadData() { ++ptr; }
2077 void ref()
2078 {
2079 // if we're called after the destructor, we'll crash
2080 ptr->ref();
2081 }
2082};
2083
2084class StrongThread: public QThread
2085{
2086protected:
2087 void run()
2088 {
2089 usleep(QRandomGenerator::global()->bounded(highest: 2000));
2090 ptr->ref();
2091 ptr.clear();
2092 }
2093public:
2094 QSharedPointer<ThreadData> ptr;
2095};
2096
2097class WeakThread: public QThread
2098{
2099protected:
2100 void run()
2101 {
2102 usleep(QRandomGenerator::global()->bounded(highest: 2000));
2103 QSharedPointer<ThreadData> ptr = weak;
2104 if (ptr)
2105 ptr->ref();
2106 ptr.clear();
2107 }
2108public:
2109 QWeakPointer<ThreadData> weak;
2110};
2111
2112void tst_QSharedPointer::threadStressTest_data()
2113{
2114 QTest::addColumn<int>(name: "strongThreadCount");
2115 QTest::addColumn<int>(name: "weakThreadCount");
2116
2117 QTest::newRow(dataTag: "0+0") << 0 << 0;
2118 QTest::newRow(dataTag: "1+0") << 1 << 0;
2119 QTest::newRow(dataTag: "2+0") << 2 << 0;
2120 QTest::newRow(dataTag: "10+0") << 10 << 0;
2121
2122 QTest::newRow(dataTag: "0+1") << 0 << 1;
2123 QTest::newRow(dataTag: "1+1") << 1 << 1;
2124
2125 QTest::newRow(dataTag: "2+10") << 2 << 10;
2126
2127 QTest::newRow(dataTag: "5+10") << 5 << 10;
2128 QTest::newRow(dataTag: "5+30") << 5 << 30;
2129
2130 QTest::newRow(dataTag: "100+100") << 100 << 100;
2131}
2132
2133void tst_QSharedPointer::threadStressTest()
2134{
2135 QFETCH(int, strongThreadCount);
2136 QFETCH(int, weakThreadCount);
2137
2138 int guard1[128];
2139 QAtomicInt counter;
2140 int guard2[128];
2141
2142 memset(s: guard1, c: 0, n: sizeof guard1);
2143 memset(s: guard2, c: 0, n: sizeof guard2);
2144
2145 for (int r = 0; r < 5; ++r) {
2146 QVector<QThread*> allThreads(6 * qMax(a: strongThreadCount, b: weakThreadCount) + 3, 0);
2147 QSharedPointer<ThreadData> base = QSharedPointer<ThreadData>(new ThreadData(&counter));
2148 counter.storeRelaxed(newValue: 0);
2149
2150 // set the pointers
2151 for (int i = 0; i < strongThreadCount; ++i) {
2152 StrongThread *t = new StrongThread;
2153 t->ptr = base;
2154 allThreads[2 * i] = t;
2155 }
2156 for (int i = 0; i < weakThreadCount; ++i) {
2157 WeakThread *t = new WeakThread;
2158 t->weak = base;
2159 allThreads[6 * i + 3] = t;
2160 }
2161
2162 base.clear();
2163
2164 // start threads
2165 for (int i = 0; i < allThreads.count(); ++i)
2166 if (allThreads[i]) allThreads[i]->start();
2167
2168 // wait for them to finish
2169 for (int i = 0; i < allThreads.count(); ++i)
2170 if (allThreads[i]) allThreads[i]->wait();
2171 qDeleteAll(c: allThreads);
2172
2173 // ensure the guards aren't touched
2174 for (uint i = 0; i < sizeof guard1 / sizeof guard1[0]; ++i)
2175 QVERIFY(!guard1[i]);
2176 for (uint i = 0; i < sizeof guard2 / sizeof guard2[0]; ++i)
2177 QVERIFY(!guard2[i]);
2178
2179 // verify that the count is the right range
2180 int minValue = strongThreadCount;
2181 int maxValue = strongThreadCount + weakThreadCount;
2182 QVERIFY(counter.loadRelaxed() >= minValue);
2183 QVERIFY(counter.loadRelaxed() <= maxValue);
2184 }
2185}
2186
2187template<typename Container, bool Ordered>
2188void hashAndMapTest()
2189{
2190 typedef typename Container::key_type Key;
2191 typedef typename Container::mapped_type Value;
2192
2193 Container c;
2194 QVERIFY(c.isEmpty());
2195
2196 Key k0;
2197 c.insert(k0, Value(0));
2198 QVERIFY(!c.isEmpty());
2199
2200 typename Container::iterator it;
2201 it = c.find(k0);
2202 QVERIFY(it != c.end());
2203 it = c.find(Key());
2204 QVERIFY(it != c.end());
2205 it = c.find(Key(0));
2206 QVERIFY(it != c.end());
2207
2208 Key k1(new typename Key::value_type(42));
2209 it = c.find(k1);
2210 QVERIFY(it == c.end());
2211
2212 c.insert(k1, Value(42));
2213 it = c.find(k1);
2214 QVERIFY(it != c.end());
2215 QVERIFY(it != c.find(Key()));
2216
2217 if (Ordered) {
2218 QVERIFY(k0 < k1);
2219
2220 it = c.begin();
2221 QCOMPARE(it.key(), k0);
2222 QCOMPARE(it.value(), Value(0));
2223
2224 ++it;
2225 QCOMPARE(it.key(), k1);
2226 QCOMPARE(it.value(), Value(42));
2227
2228 ++it;
2229 QVERIFY(it == c.end());
2230 }
2231
2232 c.insertMulti(k1, Value(47));
2233 it = c.find(k1);
2234 QVERIFY(it != c.end());
2235 QCOMPARE(it.key(), k1);
2236 ++it;
2237 QVERIFY(it != c.end());
2238 QCOMPARE(it.key(), k1);
2239 ++it;
2240 if (Ordered)
2241 QVERIFY(it == c.end());
2242}
2243
2244void tst_QSharedPointer::map()
2245{
2246 hashAndMapTest<QMap<QSharedPointer<int>, int>, true>();
2247}
2248
2249void tst_QSharedPointer::hash()
2250{
2251 hashAndMapTest<QHash<QSharedPointer<int>, int>, false>();
2252}
2253
2254void tst_QSharedPointer::validConstructs()
2255{
2256 {
2257 Data *aData = new Data;
2258 QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);
2259
2260 ptr1 = ptr1; // valid
2261
2262 QSharedPointer<Data> ptr2(ptr1);
2263
2264 ptr1 = ptr2;
2265 ptr2 = ptr1;
2266
2267 ptr1 = QSharedPointer<Data>();
2268 ptr1 = ptr2;
2269 }
2270}
2271
2272typedef bool (QTest::QExternalTest:: * TestFunction)(const QByteArray &body);
2273Q_DECLARE_METATYPE(TestFunction)
2274void tst_QSharedPointer::invalidConstructs_data()
2275{
2276 QTest::addColumn<TestFunction>(name: "testFunction");
2277 QTest::addColumn<QString>(name: "code");
2278 QTest::newRow(dataTag: "sanity-checking") << &QTest::QExternalTest::tryCompile << "";
2279
2280 // QSharedPointer<void> is not allowed
2281 QTest::newRow(dataTag: "void") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer<void> ptr;";
2282
2283 // implicit initialization
2284 QTest::newRow(dataTag: "implicit-initialization1")
2285 << &QTest::QExternalTest::tryCompileFail
2286 << "QSharedPointer<Data> ptr = new Data;";
2287 QTest::newRow(dataTag: "implicit-initialization2")
2288 << &QTest::QExternalTest::tryCompileFail
2289 << "QSharedPointer<Data> ptr;"
2290 "ptr = new Data;";
2291 QTest::newRow(dataTag: "implicit-initialization3")
2292 << &QTest::QExternalTest::tryCompileFail
2293 << "QWeakPointer<Data> ptr = new Data;";
2294 QTest::newRow(dataTag: "implicit-initialization4")
2295 << &QTest::QExternalTest::tryCompileFail
2296 << "QWeakPointer<Data> ptr;"
2297 "ptr = new Data;";
2298
2299 // use of forward-declared class
2300 QTest::newRow(dataTag: "creating-forward-declaration")
2301 << &QTest::QExternalTest::tryCompileFail
2302 << "QSharedPointer<ForwardDeclared>::create();";
2303
2304 // upcast without cast operator:
2305 QTest::newRow(dataTag: "upcast1")
2306 << &QTest::QExternalTest::tryCompileFail
2307 << "QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);\n"
2308 "QSharedPointer<DerivedData> ptr(baseptr);";
2309 QTest::newRow(dataTag: "upcast2")
2310 << &QTest::QExternalTest::tryCompileFail
2311 << "QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);\n"
2312 "QSharedPointer<DerivedData> ptr;\n"
2313 "ptr = baseptr;";
2314
2315 // dropping of const
2316 QTest::newRow(dataTag: "const-dropping1")
2317 << &QTest::QExternalTest::tryCompileFail
2318 << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
2319 "QSharedPointer<Data> ptr(baseptr);";
2320 QTest::newRow(dataTag: "const-dropping2")
2321 << &QTest::QExternalTest::tryCompileFail
2322 << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
2323 "QSharedPointer<Data> ptr;"
2324 "ptr = baseptr;";
2325 QTest::newRow(dataTag: "const-dropping-static-cast")
2326 << &QTest::QExternalTest::tryCompileFail
2327 << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
2328 "qSharedPointerCast<DerivedData>(baseptr);";
2329#ifndef QTEST_NO_RTTI
2330 QTest::newRow(dataTag: "const-dropping-dynamic-cast")
2331 << &QTest::QExternalTest::tryCompileFail
2332 << "QSharedPointer<const Data> baseptr = QSharedPointer<const Data>(new Data);\n"
2333 "qSharedPointerDynamicCast<DerivedData>(baseptr);";
2334#endif
2335 QTest::newRow(dataTag: "const-dropping-object-cast1")
2336 << &QTest::QExternalTest::tryCompileFail
2337 << "QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(new QObject);\n"
2338 "qSharedPointerObjectCast<QCoreApplication>(baseptr);";
2339 QTest::newRow(dataTag: "const-dropping-object-cast2")
2340 << &QTest::QExternalTest::tryCompileFail
2341 << "QSharedPointer<const QObject> baseptr = QSharedPointer<const QObject>(new QObject);\n"
2342 "qobject_cast<QCoreApplication *>(baseptr);";
2343
2344 // arithmethics through automatic cast operators
2345 QTest::newRow(dataTag: "arithmethic1")
2346 << &QTest::QExternalTest::tryCompileFail
2347 << "QSharedPointer<int> a;"
2348 "QSharedPointer<Data> b;\n"
2349 "if (a == b) return;";
2350 QTest::newRow(dataTag: "arithmethic2")
2351 << &QTest::QExternalTest::tryCompileFail
2352 << "QSharedPointer<int> a;"
2353 "QSharedPointer<Data> b;\n"
2354 "if (a + b) return;";
2355
2356 // two objects with the same pointer
2357 QTest::newRow(dataTag: "same-pointer")
2358 << &QTest::QExternalTest::tryRunFail
2359 << "Data *aData = new Data;\n"
2360 "QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);\n"
2361 "QSharedPointer<Data> ptr2 = QSharedPointer<Data>(aData);\n";
2362
2363 // two QObjects with the same pointer
2364 QTest::newRow(dataTag: "same-pointer-to-qobject")
2365 << &QTest::QExternalTest::tryRunFail
2366 << "QObject *anObj = new QObject;\n"
2367 "QSharedPointer<QObject> ptr1 = QSharedPointer<QObject>(anObj);\n"
2368 "QSharedPointer<QObject> ptr2 = QSharedPointer<QObject>(anObj);\n";
2369
2370 // re-creation:
2371 QTest::newRow(dataTag: "re-creation")
2372 << &QTest::QExternalTest::tryRunFail
2373 << "Data *aData = new Data;\n"
2374 "QSharedPointer<Data> ptr1 = QSharedPointer<Data>(aData);"
2375 "ptr1 = QSharedPointer<Data>(aData);";
2376
2377 // any type of cast for unrelated types:
2378 // (we have no reinterpret_cast)
2379 QTest::newRow(dataTag: "invalid-cast1")
2380 << &QTest::QExternalTest::tryCompileFail
2381 << "QSharedPointer<Data> ptr1;\n"
2382 "QSharedPointer<int> ptr2 = qSharedPointerCast<int>(ptr1);";
2383#ifndef QTEST_NO_RTTI
2384 QTest::newRow(dataTag: "invalid-cast2")
2385 << &QTest::QExternalTest::tryCompileFail
2386 << "QSharedPointer<Data> ptr1;\n"
2387 "QSharedPointer<int> ptr2 = qSharedPointerDynamicCast<int>(ptr1);";
2388#endif
2389 QTest::newRow(dataTag: "invalid-cast3")
2390 << &QTest::QExternalTest::tryCompileFail
2391 << "QSharedPointer<Data> ptr1;\n"
2392 "QSharedPointer<int> ptr2 = qSharedPointerConstCast<int>(ptr1);";
2393 QTest::newRow(dataTag: "invalid-cast4")
2394 << &QTest::QExternalTest::tryCompileFail
2395 << "QSharedPointer<Data> ptr1;\n"
2396 "QSharedPointer<int> ptr2 = qSharedPointerObjectCast<int>(ptr1);";
2397
2398 QTest::newRow(dataTag: "weak-pointer-from-regular-pointer")
2399 << &QTest::QExternalTest::tryCompileFail
2400 << "Data *ptr = 0;\n"
2401 "QWeakPointer<Data> weakptr(ptr);\n";
2402
2403 QTest::newRow(dataTag: "shared-pointer-implicit-from-uninitialized")
2404 << &QTest::QExternalTest::tryCompileFail
2405 << "Data *ptr = 0;\n"
2406 "QSharedPointer<Data> weakptr = Qt::Uninitialized;\n";
2407
2408 QTest::newRow(dataTag: "incompatible-custom-deleter1")
2409 << &QTest::QExternalTest::tryCompileFail
2410 << "extern void incompatibleCustomDeleter(int *);\n"
2411 "QSharedPointer<Data> ptr(new Data, incompatibleCustomDeleter);\n";
2412 QTest::newRow(dataTag: "incompatible-custom-deleter2")
2413 << &QTest::QExternalTest::tryCompileFail
2414 << "struct IncompatibleCustomDeleter { void operator()(int *); };\n"
2415 "QSharedPointer<Data> ptr(new Data, IncompatibleCustomDeleter());\n";
2416 QTest::newRow(dataTag: "incompatible-custom-lambda-deleter")
2417 << &QTest::QExternalTest::tryCompileFail
2418 << "QSharedPointer<Data> ptr(new Data, [](int *) {});\n";
2419
2420 QTest::newRow(dataTag: "incompatible-overload")
2421 << &QTest::QExternalTest::tryCompileFail
2422 << "void foo(QSharedPointer<DerivedData>) {}\n"
2423 "void bar() { foo(QSharedPointer<Data>()); }\n";
2424}
2425
2426void tst_QSharedPointer::invalidConstructs()
2427{
2428#ifdef Q_CC_MINGW
2429 QSKIP("The maintainer of QSharedPointer: 'We don't know what the problem is so skip the tests.'");
2430#endif
2431#ifdef QTEST_CROSS_COMPILED
2432 QSKIP("This test does not work on cross compiled systems");
2433#endif
2434
2435 QTest::QExternalTest test;
2436 test.setQtModules(QTest::QExternalTest::QtCore);
2437 test.setProgramHeader(
2438 "#define QT_SHAREDPOINTER_TRACK_POINTERS\n"
2439 "#define QT_DEBUG\n"
2440 "#include <QtCore/qsharedpointer.h>\n"
2441 "#include <QtCore/qcoreapplication.h>\n"
2442 "\n"
2443 "struct Data { int i; };\n"
2444 "struct DerivedData: public Data { int j; };\n"
2445 "\n"
2446 "class ForwardDeclared;\n"
2447 );
2448
2449 QFETCH(QString, code);
2450 static bool sane = true;
2451 if (code.isEmpty()) {
2452 if (!test.tryRun(body: "")
2453 || !test.tryRunFail(body: "exit(1);")
2454 || !test.tryRun(body: "QSharedPointer<Data> baseptr; QSharedPointer<DerivedData> ptr;")) {
2455 sane = false;
2456 qWarning(msg: "Sanity checking failed\nCode:\n%s\n",
2457 qPrintable(test.errorReport()));
2458 }
2459 }
2460 if (!sane)
2461 QFAIL("External testing failed sanity checking, cannot proceed");
2462
2463 QFETCH(TestFunction, testFunction);
2464
2465 QByteArray body = code.toLatin1();
2466
2467 bool result = (test.*testFunction)(body);
2468 if (!result || qgetenv(varName: "QTEST_EXTERNAL_DEBUG").toInt() > 0) {
2469 qDebug(msg: "External test output:");
2470#ifdef Q_CC_MSVC
2471 // MSVC prints errors to stdout
2472 printf("%s\n", test.standardOutput().constData());
2473#endif
2474 printf(format: "%s\n", test.standardError().constData());
2475 }
2476 if (!result) {
2477 qWarning(msg: "External code testing failed\nCode:\n%s\n", body.constData());
2478 QFAIL("Fail");
2479 }
2480}
2481
2482void tst_QSharedPointer::qvariantCast()
2483{
2484 QSharedPointer<QFile> sp = QSharedPointer<QFile>::create();
2485 sp->setObjectName("A test name");
2486 QVariant v = QVariant::fromValue(value: sp);
2487
2488 {
2489 QSharedPointer<QObject> other = qSharedPointerFromVariant<QObject>(variant: v);
2490 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
2491 }
2492 {
2493 QSharedPointer<QIODevice> other = qSharedPointerFromVariant<QIODevice>(variant: v);
2494 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
2495 }
2496 {
2497 QSharedPointer<QFile> other = qSharedPointerFromVariant<QFile>(variant: v);
2498 QCOMPARE(other->objectName(), QString::fromLatin1("A test name"));
2499 }
2500 {
2501 QSharedPointer<QThread> other = qSharedPointerFromVariant<QThread>(variant: v);
2502 QVERIFY(!other);
2503 }
2504 // Intentionally does not compile.
2505// QSharedPointer<int> sop = qSharedPointerFromVariant<int>(v);
2506
2507#if QT_DEPRECATED_SINCE(5, 0)
2508 v = QVariant::fromValue(value: sp.toWeakRef());
2509
2510 {
2511 QWeakPointer<QObject> other = qWeakPointerFromVariant<QObject>(variant: v);
2512 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2513 }
2514 {
2515 QWeakPointer<QIODevice> other = qWeakPointerFromVariant<QIODevice>(variant: v);
2516 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2517 }
2518 {
2519 QWeakPointer<QFile> other = qWeakPointerFromVariant<QFile>(variant: v);
2520 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2521 }
2522 {
2523 QWeakPointer<QThread> other = qWeakPointerFromVariant<QThread>(variant: v);
2524 QVERIFY(!other);
2525 }
2526
2527 // Intentionally does not compile.
2528// QWeakPointer<int> sop = qWeakPointerFromVariant<int>(v);
2529
2530 QFile file;
2531 QWeakPointer<QFile> tracking = &file;
2532 tracking.data()->setObjectName("A test name");
2533 v = QVariant::fromValue(value: tracking);
2534
2535 {
2536 QWeakPointer<QObject> other = qWeakPointerFromVariant<QObject>(variant: v);
2537 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2538 }
2539 {
2540 QWeakPointer<QIODevice> other = qWeakPointerFromVariant<QIODevice>(variant: v);
2541 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2542 }
2543 {
2544 QWeakPointer<QFile> other = qWeakPointerFromVariant<QFile>(variant: v);
2545 QCOMPARE(other.data()->objectName(), QString::fromLatin1("A test name"));
2546 }
2547 {
2548 QWeakPointer<QThread> other = qWeakPointerFromVariant<QThread>(variant: v);
2549 QVERIFY(!other);
2550 }
2551#endif
2552}
2553
2554class SomeClass : public QEnableSharedFromThis<SomeClass>
2555{
2556public:
2557 SomeClass()
2558 {
2559 }
2560
2561 QSharedPointer<SomeClass> getSharedPtr()
2562 {
2563 return sharedFromThis();
2564 }
2565
2566 QSharedPointer<const SomeClass> getSharedPtr() const
2567 {
2568 return sharedFromThis();
2569 }
2570
2571 Data data;
2572};
2573
2574void tst_QSharedPointer::sharedFromThis()
2575{
2576 const int generations = Data::generationCounter;
2577 const int destructions = Data::destructorCounter;
2578
2579 {
2580 SomeClass sc;
2581 QSharedPointer<SomeClass> scp = sc.sharedFromThis();
2582 QVERIFY(scp.isNull());
2583 QCOMPARE(Data::generationCounter, generations + 1);
2584 QCOMPARE(Data::destructorCounter, destructions);
2585
2586 QSharedPointer<const SomeClass> const_scp = sc.sharedFromThis();
2587 QVERIFY(const_scp.isNull());
2588 QCOMPARE(Data::generationCounter, generations + 1);
2589 QCOMPARE(Data::destructorCounter, destructions);
2590
2591 QWeakPointer<SomeClass> wcp = sc.sharedFromThis();
2592 QVERIFY(wcp.isNull());
2593 QCOMPARE(Data::generationCounter, generations + 1);
2594 QCOMPARE(Data::destructorCounter, destructions);
2595
2596 QWeakPointer<const SomeClass> const_wcp = sc.sharedFromThis();
2597 QVERIFY(const_wcp.isNull());
2598 QCOMPARE(Data::generationCounter, generations + 1);
2599 QCOMPARE(Data::destructorCounter, destructions);
2600 }
2601
2602 QCOMPARE(Data::generationCounter, generations + 1);
2603 QCOMPARE(Data::destructorCounter, destructions + 1);
2604
2605 {
2606 const SomeClass sc;
2607 QSharedPointer<const SomeClass> const_scp = sc.sharedFromThis();
2608 QVERIFY(const_scp.isNull());
2609 QCOMPARE(Data::generationCounter, generations + 2);
2610 QCOMPARE(Data::destructorCounter, destructions + 1);
2611
2612 QWeakPointer<const SomeClass> const_wcp = sc.sharedFromThis();
2613 QVERIFY(const_wcp.isNull());
2614 QCOMPARE(Data::generationCounter, generations + 2);
2615 QCOMPARE(Data::destructorCounter, destructions + 1);
2616 }
2617
2618 QCOMPARE(Data::generationCounter, generations + 2);
2619 QCOMPARE(Data::destructorCounter, destructions + 2);
2620
2621 {
2622 SomeClass *sc = new SomeClass;
2623 QCOMPARE(Data::generationCounter, generations + 3);
2624 QCOMPARE(Data::destructorCounter, destructions + 2);
2625
2626 QSharedPointer<SomeClass> scp;
2627 QVERIFY(scp.isNull());
2628 QCOMPARE(Data::generationCounter, generations + 3);
2629 QCOMPARE(Data::destructorCounter, destructions + 2);
2630
2631 scp = sc->sharedFromThis();
2632 QVERIFY(scp.isNull());
2633 QCOMPARE(Data::generationCounter, generations + 3);
2634 QCOMPARE(Data::destructorCounter, destructions + 2);
2635
2636 scp = QSharedPointer<SomeClass>(sc);
2637 QVERIFY(!scp.isNull());
2638 QCOMPARE(scp.data(), sc);
2639 QCOMPARE(Data::generationCounter, generations + 3);
2640 QCOMPARE(Data::destructorCounter, destructions + 2);
2641
2642 QSharedPointer<SomeClass> scp2;
2643 QVERIFY(scp2.isNull());
2644 QCOMPARE(Data::generationCounter, generations + 3);
2645 QCOMPARE(Data::destructorCounter, destructions + 2);
2646
2647 scp2 = sc->sharedFromThis();
2648 QVERIFY(!scp2.isNull());
2649 QVERIFY(scp == scp2);
2650 QCOMPARE(scp2.data(), sc);
2651 QCOMPARE(Data::generationCounter, generations + 3);
2652 QCOMPARE(Data::destructorCounter, destructions + 2);
2653
2654 QSharedPointer<const SomeClass> scp3;
2655 QVERIFY(scp3.isNull());
2656 QCOMPARE(Data::generationCounter, generations + 3);
2657 QCOMPARE(Data::destructorCounter, destructions + 2);
2658
2659 scp3 = sc->sharedFromThis();
2660 QVERIFY(!scp3.isNull());
2661 QVERIFY(scp == scp3);
2662 QVERIFY(scp2 == scp3);
2663 QCOMPARE(scp3.data(), sc);
2664 QCOMPARE(Data::generationCounter, generations + 3);
2665 QCOMPARE(Data::destructorCounter, destructions + 2);
2666
2667 QSharedPointer<SomeClass> scp4;
2668 QVERIFY(scp4.isNull());
2669 QCOMPARE(Data::generationCounter, generations + 3);
2670 QCOMPARE(Data::destructorCounter, destructions + 2);
2671
2672 scp4 = sc->getSharedPtr();
2673 QVERIFY(!scp4.isNull());
2674 QVERIFY(scp == scp4);
2675 QVERIFY(scp2 == scp4);
2676 QVERIFY(scp3 == scp4);
2677 QCOMPARE(scp4.data(), sc);
2678 QCOMPARE(Data::generationCounter, generations + 3);
2679 QCOMPARE(Data::destructorCounter, destructions + 2);
2680
2681 QSharedPointer<const SomeClass> scp5;
2682 QVERIFY(scp5.isNull());
2683 QCOMPARE(Data::generationCounter, generations + 3);
2684 QCOMPARE(Data::destructorCounter, destructions + 2);
2685
2686 scp5 = const_cast<const SomeClass *>(sc)->getSharedPtr();
2687 QVERIFY(!scp4.isNull());
2688 QVERIFY(scp == scp5);
2689 QVERIFY(scp2 == scp5);
2690 QVERIFY(scp3 == scp5);
2691 QVERIFY(scp4 == scp5);
2692 QCOMPARE(scp5.data(), sc);
2693 QCOMPARE(Data::generationCounter, generations + 3);
2694 QCOMPARE(Data::destructorCounter, destructions + 2);
2695 }
2696
2697 QCOMPARE(Data::generationCounter, generations + 3);
2698 QCOMPARE(Data::destructorCounter, destructions + 3);
2699
2700 QSharedPointer<SomeClass> scp;
2701
2702 QVERIFY(scp.isNull());
2703
2704 {
2705 QSharedPointer<SomeClass> scp2(new SomeClass());
2706 QVERIFY(!scp2.isNull());
2707
2708 scp = scp2->sharedFromThis();
2709 QVERIFY(!scp.isNull());
2710
2711 QVERIFY(scp == scp2);
2712 QCOMPARE(Data::generationCounter, generations + 4);
2713 QCOMPARE(Data::destructorCounter, destructions + 3);
2714 }
2715
2716
2717 QCOMPARE(Data::generationCounter, generations + 4);
2718 QCOMPARE(Data::destructorCounter, destructions + 3);
2719 QVERIFY(!scp.isNull());
2720
2721 {
2722 QSharedPointer<const SomeClass> scp2;
2723 scp2 = scp->sharedFromThis();
2724 QVERIFY(!scp2.isNull());
2725
2726 QVERIFY(scp == scp2);
2727 QCOMPARE(Data::generationCounter, generations + 4);
2728 QCOMPARE(Data::destructorCounter, destructions + 3);
2729 }
2730
2731 QCOMPARE(Data::generationCounter, generations + 4);
2732 QCOMPARE(Data::destructorCounter, destructions + 3);
2733 QVERIFY(!scp.isNull());
2734
2735 {
2736 QSharedPointer<SomeClass> scp2;
2737 scp2 = scp->getSharedPtr();
2738 QVERIFY(!scp2.isNull());
2739
2740 QVERIFY(scp == scp2);
2741 QCOMPARE(Data::generationCounter, generations + 4);
2742 QCOMPARE(Data::destructorCounter, destructions + 3);
2743 }
2744
2745 QCOMPARE(Data::generationCounter, generations + 4);
2746 QCOMPARE(Data::destructorCounter, destructions + 3);
2747 QVERIFY(!scp.isNull());
2748
2749 {
2750 QSharedPointer<const SomeClass> scp2;
2751 scp2 = qSharedPointerConstCast<const SomeClass>(src: scp)->getSharedPtr();
2752 QVERIFY(!scp2.isNull());
2753
2754 QVERIFY(scp == scp2);
2755 QCOMPARE(Data::generationCounter, generations + 4);
2756 QCOMPARE(Data::destructorCounter, destructions + 3);
2757 }
2758
2759 QCOMPARE(Data::generationCounter, generations + 4);
2760 QCOMPARE(Data::destructorCounter, destructions + 3);
2761 QVERIFY(!scp.isNull());
2762
2763 {
2764 QSharedPointer<SomeClass> scp2;
2765 scp2 = scp->sharedFromThis();
2766 QVERIFY(!scp2.isNull());
2767
2768 QVERIFY(scp == scp2);
2769 QCOMPARE(Data::generationCounter, generations + 4);
2770 QCOMPARE(Data::destructorCounter, destructions + 3);
2771
2772 scp2.clear();
2773
2774 QCOMPARE(Data::generationCounter, generations + 4);
2775 QCOMPARE(Data::destructorCounter, destructions + 3);
2776 QVERIFY(!scp.isNull());
2777 QVERIFY(scp2.isNull());
2778 }
2779
2780 QCOMPARE(Data::generationCounter, generations + 4);
2781 QCOMPARE(Data::destructorCounter, destructions + 3);
2782 QVERIFY(!scp.isNull());
2783
2784 scp.clear();
2785
2786 QCOMPARE(Data::generationCounter, generations + 4);
2787 QCOMPARE(Data::destructorCounter, destructions + 4);
2788
2789 {
2790 QSharedPointer<SomeClass> scp2 = QSharedPointer<SomeClass>::create();
2791 QVERIFY(!scp2.isNull());
2792
2793 scp = scp2->sharedFromThis();
2794 QVERIFY(!scp.isNull());
2795
2796 QVERIFY(scp == scp2);
2797 QCOMPARE(Data::generationCounter, generations + 5);
2798 QCOMPARE(Data::destructorCounter, destructions + 4);
2799 }
2800 QCOMPARE(Data::generationCounter, generations + 5);
2801 QCOMPARE(Data::destructorCounter, destructions + 4);
2802
2803 scp.clear();
2804
2805 QCOMPARE(Data::generationCounter, generations + 5);
2806 QCOMPARE(Data::destructorCounter, destructions + 5);
2807
2808 {
2809 QSharedPointer<const SomeClass> scp2(new SomeClass());
2810 QVERIFY(!scp2.isNull());
2811 QCOMPARE(Data::generationCounter, generations + 6);
2812 QCOMPARE(Data::destructorCounter, destructions + 5);
2813
2814 QWeakPointer<const SomeClass> wcp2(scp2.constCast<SomeClass>());
2815 QVERIFY(!wcp2.isNull());
2816 QCOMPARE(Data::generationCounter, generations + 6);
2817 QCOMPARE(Data::destructorCounter, destructions + 5);
2818 }
2819
2820 QCOMPARE(Data::generationCounter, generations + 6);
2821 QCOMPARE(Data::destructorCounter, destructions + 6);
2822}
2823
2824#ifndef QT_NO_EXCEPTIONS
2825class ThrowData: public Data
2826{
2827public:
2828 static int childDestructorCounter;
2829 static int childGenerationCounter;
2830
2831 ThrowData()
2832 {
2833 childGenerationCounter++;
2834 throw QStringLiteral("Dummy exception");
2835 }
2836
2837 ~ThrowData()
2838 {
2839 childDestructorCounter++;
2840 }
2841};
2842int ThrowData::childDestructorCounter = 0;
2843int ThrowData::childGenerationCounter = 0;
2844#endif // !QT_NO_EXCEPTIONS
2845
2846void tst_QSharedPointer::constructorThrow()
2847{
2848#ifndef QT_NO_EXCEPTIONS
2849 int generation = Data::generationCounter;
2850 int destructorCounter = Data::destructorCounter;
2851
2852 int childGeneration = ThrowData::childGenerationCounter;
2853 int childDestructorCounter = ThrowData::childDestructorCounter;
2854
2855 QSharedPointer<ThrowData> ptr;
2856 QVERIFY_EXCEPTION_THROWN(ptr = QSharedPointer<ThrowData>::create(), QString);
2857 QVERIFY(ptr.isNull());
2858 QCOMPARE(ThrowData::childGenerationCounter, childGeneration + 1);
2859 // destructor should never be called, if a constructor throws
2860 // an exception
2861 QCOMPARE(ThrowData::childDestructorCounter, childDestructorCounter);
2862
2863 QCOMPARE(Data::generationCounter, generation + 1);
2864 // but base class constructor doesn't throw, so base class destructor
2865 // should be called
2866 QCOMPARE(Data::destructorCounter, destructorCounter + 1);
2867#else
2868 QSKIP("Needs exceptions");
2869#endif // !QT_NO_EXCEPTIONS
2870}
2871
2872namespace ReentrancyWhileDestructing {
2873 struct IB
2874 {
2875 virtual ~IB() {}
2876 };
2877
2878 struct IA
2879 {
2880 virtual QSharedPointer<IB> getB() = 0;
2881 };
2882
2883 struct B: public IB
2884 {
2885 IA *m_a;
2886 B(IA *a_a) :m_a(a_a)
2887 { }
2888 ~B()
2889 {
2890 QSharedPointer<IB> b = m_a->getB();
2891 }
2892 };
2893
2894 struct A: public IA
2895 {
2896 QSharedPointer<IB> b;
2897
2898 virtual QSharedPointer<IB> getB()
2899 {
2900 return b;
2901 }
2902
2903 A()
2904 {
2905 b = QSharedPointer<IB>(new B(this));
2906 }
2907
2908 ~A()
2909 {
2910 b.clear();
2911 }
2912 };
2913}
2914
2915// This is a regression test for QTBUG-11730, where there would be a crash if
2916// the destructor of a QSharedPointer object being deleted recursed back into
2917// the same QSharedPointer object. There are no explicit verification steps
2918// in this test -- it is sufficient that the code does not crash.
2919void tst_QSharedPointer::reentrancyWhileDestructing()
2920{
2921 ReentrancyWhileDestructing::A obj;
2922}
2923
2924namespace {
2925struct Base1 {};
2926struct Base2 {};
2927
2928struct Child1 : Base1 {};
2929struct Child2 : Base2 {};
2930
2931template<template<typename> class SmartPtr>
2932struct Overloaded
2933{
2934 std::array<int, 1> call(const SmartPtr<const Base1> &)
2935 {
2936 return {};
2937 }
2938 std::array<int, 2> call(const SmartPtr<const Base2> &)
2939 {
2940 return {};
2941 }
2942 static const Q_CONSTEXPR uint base1Called = sizeof(std::array<int, 1>);
2943 static const Q_CONSTEXPR uint base2Called = sizeof(std::array<int, 2>);
2944
2945 void test()
2946 {
2947#define QVERIFY_CALLS(expr, base) Q_STATIC_ASSERT(sizeof(call(expr)) == base##Called)
2948 QVERIFY_CALLS(SmartPtr<Base1>{}, base1);
2949 QVERIFY_CALLS(SmartPtr<Base2>{}, base2);
2950 QVERIFY_CALLS(SmartPtr<const Base1>{}, base1);
2951 QVERIFY_CALLS(SmartPtr<const Base2>{}, base2);
2952 QVERIFY_CALLS(SmartPtr<Child1>{}, base1);
2953 QVERIFY_CALLS(SmartPtr<Child2>{}, base2);
2954 QVERIFY_CALLS(SmartPtr<const Child1>{}, base1);
2955 QVERIFY_CALLS(SmartPtr<const Child2>{}, base2);
2956#undef QVERIFY_CALLS
2957 }
2958};
2959}
2960
2961void tst_QSharedPointer::overloads()
2962{
2963 Overloaded<QSharedPointer> sharedOverloaded;
2964 sharedOverloaded.test();
2965 Overloaded<QWeakPointer> weakOverloaded;
2966 weakOverloaded.test();
2967}
2968
2969QTEST_MAIN(tst_QSharedPointer)
2970#include "tst_qsharedpointer.moc"
2971

source code of qtbase/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp