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
|
||||
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,
|
||||
the deleteLater() and parent-child relationship in QObject only decrease
|
||||
the strong reference count, instead of deleting the object.
|
||||
/*!
|
||||
\internal
|
||||
This function is called when a QSharedPointer is created from a QWeakPointer
|
||||
|
||||
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);
|
||||
QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
|
||||
|
||||
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();
|
||||
if (strongref.load() < 0)
|
||||
qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
|
||||
}
|
||||
|
||||
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
|
||||
|
@ -192,7 +192,9 @@ namespace QtSharedPointer {
|
||||
#ifndef QT_NO_QOBJECT
|
||||
Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
|
||||
Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
|
||||
Q_CORE_EXPORT void checkQObjectShared(const QObject *);
|
||||
#endif
|
||||
inline void checkQObjectShared(...) { }
|
||||
inline void setQObjectShared(...) { }
|
||||
};
|
||||
// sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit)
|
||||
@ -432,11 +434,13 @@ namespace QtSharedPointer {
|
||||
tmp = o->strongref.load(); // failed, try again
|
||||
}
|
||||
|
||||
if (tmp > 0)
|
||||
if (tmp > 0) {
|
||||
o->weakref.ref();
|
||||
else
|
||||
} else {
|
||||
o->checkQObjectShared(actual);
|
||||
o = 0;
|
||||
}
|
||||
}
|
||||
|
||||
qSwap(d, o);
|
||||
qSwap(this->value, actual);
|
||||
|
@ -76,6 +76,7 @@ private slots:
|
||||
void upCast();
|
||||
void qobjectWeakManagement();
|
||||
void noSharedPointerFromWeakQObject();
|
||||
void sharedPointerFromQObjectWithWeak();
|
||||
void weakQObjectFromSharedPointer();
|
||||
void objectCast();
|
||||
void differentPointers();
|
||||
@ -692,12 +693,34 @@ void tst_QSharedPointer::noSharedPointerFromWeakQObject()
|
||||
QObject obj;
|
||||
QWeakPointer<QObject> weak(&obj);
|
||||
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg , "QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
|
||||
QSharedPointer<QObject> strong = weak.toStrongRef();
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// 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"
|
||||
"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::QExternalTest::tryCompileFail
|
||||
<< "Data *ptr = 0;\n"
|
||||
|
Loading…
Reference in New Issue
Block a user