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<X> ptr(new Y);

Behaves like
   QSharedPointer<X> ptr;
   { QSharedPointer<Y> tmp(new Y); ptr = tmp; }

Change-Id: Id75834dab9ed466e94c7ffff14455d445f72592b
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
bb10
Thiago Macieira 2016-04-14 16:23:22 -07:00 committed by Marc Mutz
parent a7e3c17e75
commit e22a230a03
3 changed files with 89 additions and 3 deletions

View File

@ -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<MyObject> obj =

View File

@ -518,15 +518,15 @@ private:
inline void enableSharedFromThis(...) {}
template <typename Deleter>
inline void internalConstruct(T *ptr, Deleter deleter)
template <typename X, typename Deleter>
inline void internalConstruct(X *ptr, Deleter deleter)
{
if (!ptr) {
d = Q_NULLPTR;
return;
}
typedef QtSharedPointer::ExternalRefCountWithCustomDeleter<T, Deleter> Private;
typedef QtSharedPointer::ExternalRefCountWithCustomDeleter<X, Deleter> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
typename Private::DestroyerFn actualDeleter = &Private::safetyCheckDeleter;
# else

View File

@ -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<NVDData> ptr(new NVDData);
}
QCOMPARE(NVDData::destructorCounter, 1);
QCOMPARE(NVDDerivedData::destructorCounter, 0);
NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
{
QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData);
}
QCOMPARE(NVDData::destructorCounter, 1);
QCOMPARE(NVDDerivedData::destructorCounter, 1);
NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
{
QSharedPointer<NVDData> bptr;
QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData);
bptr = ptr;
}
QCOMPARE(NVDData::destructorCounter, 1);
QCOMPARE(NVDDerivedData::destructorCounter, 1);
NVDData::destructorCounter = NVDDerivedData::destructorCounter = 0;
{
QSharedPointer<NVDData> ptr(new NVDDerivedData);
}
QCOMPARE(NVDData::destructorCounter, 1);
QCOMPARE(NVDDerivedData::destructorCounter, 1);
}
void tst_QSharedPointer::lock()
{
QSharedPointer<int> sp = QSharedPointer<int>::create();
@ -1529,6 +1580,33 @@ void tst_QSharedPointer::customDeleter()
QCOMPARE(refcount, 2);
safetyCheck();
CustomDeleter<NVDData> nvdeleter;
nvdeleter.callCount = 0;
{
QSharedPointer<NVDData> ptr(new NVDData, nvdeleter);
}
QCOMPARE(nvdeleter.callCount, 1);
safetyCheck();
CustomDeleter<NVDDerivedData> nvderiveddeleter;
nvdeleter.callCount = 0;
nvderiveddeleter.callCount = 0;
{
QSharedPointer<NVDDerivedData> ptr(new NVDDerivedData, nvderiveddeleter);
}
QCOMPARE(nvdeleter.callCount, 0);
QCOMPARE(nvderiveddeleter.callCount, 1);
safetyCheck();
nvdeleter.callCount = 0;
nvderiveddeleter.callCount = 0;
{
QSharedPointer<NVDData> ptr(new NVDDerivedData, nvderiveddeleter);
}
QCOMPARE(nvdeleter.callCount, 0);
QCOMPARE(nvderiveddeleter.callCount, 1);
safetyCheck();
// a custom deleter with a different pointer parameter
{
QSharedPointer<char> ptr(static_cast<char *>(malloc(1)), free);