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:
Olivier Goffart 2011-12-23 17:13:05 +01:00 committed by Qt by Nokia
parent 281673e5d3
commit 497622cafe
3 changed files with 44 additions and 25 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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"