From e22a230a039a392e71322cb63610d07885a45168 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 14 Apr 2016 16:23:22 -0700 Subject: Make QSharedPointer without custom deleters call the correct destructor Where "correct" is defined by what std::shared_ptr does as well as what happens when an intermediate QSharedPointer of the exact type of the constructor behaves That is, QSharedPointer ptr(new Y); Behaves like QSharedPointer ptr; { QSharedPointer tmp(new Y); ptr = tmp; } Change-Id: Id75834dab9ed466e94c7ffff14455d445f72592b Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Marc Mutz --- src/corelib/tools/qsharedpointer.cpp | 8 +++ src/corelib/tools/qsharedpointer_impl.h | 6 +- .../tools/qsharedpointer/tst_qsharedpointer.cpp | 78 ++++++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index f420c6237b..c369ff8697 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -447,6 +447,11 @@ Creates a QSharedPointer that points to \a ptr. The pointer \a ptr becomes managed by this QSharedPointer and must not be passed to another QSharedPointer object or deleted outside this object. + + Since Qt 5.8, when the last reference to this QSharedPointer gets + destroyed, \a ptr will be deleted by calling \c X's destructor (even if \c + X is not the same as QSharedPointer's template parameter \c T). Previously, + the destructor for \c T was called. */ /*! @@ -477,6 +482,9 @@ } \endcode + Note that the custom deleter function will be called with a pointer to type + \c X, even if the QSharedPointer template parameter \c T is not the same. + It is also possible to specify a member function directly, as in: \code QSharedPointer obj = diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index b9b29e926d..bbac2d0327 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -518,15 +518,15 @@ private: inline void enableSharedFromThis(...) {} - template - inline void internalConstruct(T *ptr, Deleter deleter) + template + inline void internalConstruct(X *ptr, Deleter deleter) { if (!ptr) { d = Q_NULLPTR; return; } - typedef QtSharedPointer::ExternalRefCountWithCustomDeleter Private; + typedef QtSharedPointer::ExternalRefCountWithCustomDeleter Private; # ifdef QT_SHAREDPOINTER_TRACK_POINTERS typename Private::DestroyerFn actualDeleter = &Private::safetyCheckDeleter; # else diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index f48e81ed91..7998f7b7fd 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -63,6 +63,7 @@ private slots: void useOfForwardDeclared(); void memoryManagement(); void dropLastReferenceOfForwardDeclared(); + void nonVirtualDestructors(); void lock(); void downCast(); void functionCallDownCast(); @@ -603,6 +604,56 @@ void tst_QSharedPointer::dropLastReferenceOfForwardDeclared() QCOMPARE(forwardDeclaredDestructorRunCount, 1); } +// NVD for "non-virtual destructor" +struct NVDData +{ + static int destructorCounter; + ~NVDData() { ++destructorCounter; } + + int dummy; +}; +int NVDData::destructorCounter; + +struct NVDDerivedData : NVDData +{ + static int destructorCounter; + ~NVDDerivedData() { ++destructorCounter; } +}; +int NVDDerivedData::destructorCounter; + +void tst_QSharedPointer::nonVirtualDestructors() +{ + NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0; + { + QSharedPointer ptr(new NVDData); + } + QCOMPARE(NVDData::destructorCounter, 1); + QCOMPARE(NVDDerivedData::destructorCounter, 0); + + NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0; + { + QSharedPointer ptr(new NVDDerivedData); + } + QCOMPARE(NVDData::destructorCounter, 1); + QCOMPARE(NVDDerivedData::destructorCounter, 1); + + NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0; + { + QSharedPointer bptr; + QSharedPointer ptr(new NVDDerivedData); + bptr = ptr; + } + QCOMPARE(NVDData::destructorCounter, 1); + QCOMPARE(NVDDerivedData::destructorCounter, 1); + + NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0; + { + QSharedPointer ptr(new NVDDerivedData); + } + QCOMPARE(NVDData::destructorCounter, 1); + QCOMPARE(NVDDerivedData::destructorCounter, 1); +} + void tst_QSharedPointer::lock() { QSharedPointer sp = QSharedPointer::create(); @@ -1529,6 +1580,33 @@ void tst_QSharedPointer::customDeleter() QCOMPARE(refcount, 2); safetyCheck(); + CustomDeleter nvdeleter; + nvdeleter.callCount = 0; + { + QSharedPointer ptr(new NVDData, nvdeleter); + } + QCOMPARE(nvdeleter.callCount, 1); + safetyCheck(); + + CustomDeleter nvderiveddeleter; + nvdeleter.callCount = 0; + nvderiveddeleter.callCount = 0; + { + QSharedPointer ptr(new NVDDerivedData, nvderiveddeleter); + } + QCOMPARE(nvdeleter.callCount, 0); + QCOMPARE(nvderiveddeleter.callCount, 1); + safetyCheck(); + + nvdeleter.callCount = 0; + nvderiveddeleter.callCount = 0; + { + QSharedPointer ptr(new NVDDerivedData, nvderiveddeleter); + } + QCOMPARE(nvdeleter.callCount, 0); + QCOMPARE(nvderiveddeleter.callCount, 1); + safetyCheck(); + // a custom deleter with a different pointer parameter { QSharedPointer ptr(static_cast(malloc(1)), free); -- cgit v1.2.3