Make it possible to put QObject tracked with QWeakPointer inside QSharedPointer
Do that by keeping the QWeakPointer that track QObject independent of the ones that track QSharedPointer. QSharedPointer do not touch the sharedRefCount in QObjectPrivate anymore When converting a QWeakPointer constructed from a QObject to a QSharedPointer, it will display a warning saying one should not do that. Task-number: QTBUG-22622 Change-Id: I3595e3e7401702410776c458687ab357ad9366ab Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com> Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com> Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
281673e5d3
commit
497622cafe
@ -1226,24 +1226,22 @@ QT_BEGIN_NAMESPACE
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
This function is called for a just-created QObject \a obj, to enable
|
This function is called for a just-created QObject \a obj, to enable
|
||||||
the use of QSharedPointer and QWeakPointer.
|
the use of QSharedPointer and QWeakPointer in the future.
|
||||||
|
*/
|
||||||
|
void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *, bool)
|
||||||
|
{}
|
||||||
|
|
||||||
When QSharedPointer is active in a QObject, the object must not be deleted
|
/*!
|
||||||
directly: the lifetime is managed by the QSharedPointer object. In that case,
|
\internal
|
||||||
the deleteLater() and parent-child relationship in QObject only decrease
|
This function is called when a QSharedPointer is created from a QWeakPointer
|
||||||
the strong reference count, instead of deleting the object.
|
|
||||||
|
We check that the QWeakPointer was really created from a QSharedPointer, and
|
||||||
|
not from a QObject.
|
||||||
*/
|
*/
|
||||||
void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *obj, bool)
|
void QtSharedPointer::ExternalRefCountData::checkQObjectShared(const QObject *)
|
||||||
{
|
{
|
||||||
Q_ASSERT(obj);
|
if (strongref.load() < 0)
|
||||||
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
|
qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
|
||||||
|
|
||||||
if (d->sharedRefcount.load() != 0)
|
|
||||||
qFatal("QSharedPointer: pointer %p already has reference counting", obj);
|
|
||||||
d->sharedRefcount.store(this);
|
|
||||||
|
|
||||||
// QObject decreases the refcount too, so increase it up
|
|
||||||
weakref.ref();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
|
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
|
||||||
|
@ -192,7 +192,9 @@ namespace QtSharedPointer {
|
|||||||
#ifndef QT_NO_QOBJECT
|
#ifndef QT_NO_QOBJECT
|
||||||
Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
|
Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
|
||||||
Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
|
Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
|
||||||
|
Q_CORE_EXPORT void checkQObjectShared(const QObject *);
|
||||||
#endif
|
#endif
|
||||||
|
inline void checkQObjectShared(...) { }
|
||||||
inline void setQObjectShared(...) { }
|
inline void setQObjectShared(...) { }
|
||||||
};
|
};
|
||||||
// sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit)
|
// sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit)
|
||||||
@ -432,11 +434,13 @@ namespace QtSharedPointer {
|
|||||||
tmp = o->strongref.load(); // failed, try again
|
tmp = o->strongref.load(); // failed, try again
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp > 0)
|
if (tmp > 0) {
|
||||||
o->weakref.ref();
|
o->weakref.ref();
|
||||||
else
|
} else {
|
||||||
|
o->checkQObjectShared(actual);
|
||||||
o = 0;
|
o = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qSwap(d, o);
|
qSwap(d, o);
|
||||||
qSwap(this->value, actual);
|
qSwap(this->value, actual);
|
||||||
|
@ -76,6 +76,7 @@ private slots:
|
|||||||
void upCast();
|
void upCast();
|
||||||
void qobjectWeakManagement();
|
void qobjectWeakManagement();
|
||||||
void noSharedPointerFromWeakQObject();
|
void noSharedPointerFromWeakQObject();
|
||||||
|
void sharedPointerFromQObjectWithWeak();
|
||||||
void weakQObjectFromSharedPointer();
|
void weakQObjectFromSharedPointer();
|
||||||
void objectCast();
|
void objectCast();
|
||||||
void differentPointers();
|
void differentPointers();
|
||||||
@ -692,12 +693,34 @@ void tst_QSharedPointer::noSharedPointerFromWeakQObject()
|
|||||||
QObject obj;
|
QObject obj;
|
||||||
QWeakPointer<QObject> weak(&obj);
|
QWeakPointer<QObject> weak(&obj);
|
||||||
|
|
||||||
|
{
|
||||||
|
QTest::ignoreMessage(QtWarningMsg , "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
|
||||||
QSharedPointer<QObject> strong = weak.toStrongRef();
|
QSharedPointer<QObject> strong = weak.toStrongRef();
|
||||||
QVERIFY(strong.isNull());
|
QVERIFY(strong.isNull());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QTest::ignoreMessage(QtWarningMsg , "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
|
||||||
|
QSharedPointer<QObject> strong = weak;
|
||||||
|
QVERIFY(strong.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(weak.data(), &obj);
|
||||||
// if something went wrong, we'll probably crash here
|
// if something went wrong, we'll probably crash here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSharedPointer::sharedPointerFromQObjectWithWeak()
|
||||||
|
{
|
||||||
|
QObject *ptr = new QObject;
|
||||||
|
QWeakPointer<QObject> weak = ptr;
|
||||||
|
{
|
||||||
|
QSharedPointer<QObject> shared(ptr);
|
||||||
|
QVERIFY(!weak.isNull());
|
||||||
|
QCOMPARE(shared.data(), ptr);
|
||||||
|
QCOMPARE(weak.data(), ptr);
|
||||||
|
}
|
||||||
|
QVERIFY(weak.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSharedPointer::weakQObjectFromSharedPointer()
|
void tst_QSharedPointer::weakQObjectFromSharedPointer()
|
||||||
{
|
{
|
||||||
// this is the inverse of the above: you're allowed to create a QWeakPointer
|
// this is the inverse of the above: you're allowed to create a QWeakPointer
|
||||||
@ -1767,12 +1790,6 @@ void tst_QSharedPointer::invalidConstructs_data()
|
|||||||
<< "Data *ptr = 0;\n"
|
<< "Data *ptr = 0;\n"
|
||||||
"QWeakPointer<Data> weakptr(ptr);\n";
|
"QWeakPointer<Data> weakptr(ptr);\n";
|
||||||
|
|
||||||
QTest::newRow("shared-pointer-from-unmanaged-qobject")
|
|
||||||
<< &QTest::QExternalTest::tryRunFail
|
|
||||||
<< "QObject *ptr = new QObject;\n"
|
|
||||||
"QWeakPointer<QObject> weak = ptr;\n" // this makes the object unmanaged
|
|
||||||
"QSharedPointer<QObject> shared(ptr);\n";
|
|
||||||
|
|
||||||
QTest::newRow("shared-pointer-implicit-from-uninitialized")
|
QTest::newRow("shared-pointer-implicit-from-uninitialized")
|
||||||
<< &QTest::QExternalTest::tryCompileFail
|
<< &QTest::QExternalTest::tryCompileFail
|
||||||
<< "Data *ptr = 0;\n"
|
<< "Data *ptr = 0;\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user