Add QEnableSharedFromThis class
It enables you to get a valid QSharedPointer instance to 'this', when all you have is 'this'. Task-number: QTBUG-7287 Change-Id: I3ed1c9c4d6b110fe02302312cc3c4a75e9d95a0c Reviewed-by: Richard J. Moore <rich@kde.org>
This commit is contained in:
parent
bc19ab03b2
commit
90a68926f3
@ -371,6 +371,43 @@
|
|||||||
\sa QSharedPointer, QScopedPointer
|
\sa QSharedPointer, QScopedPointer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QEnableSharedFromThis
|
||||||
|
\inmodule QtCore
|
||||||
|
\brief A base class that allows to obtain a QSharedPointer for an object already managed by a shared pointer
|
||||||
|
\since 5.4
|
||||||
|
|
||||||
|
You can inherit this class when you need to create a QSharedPointer
|
||||||
|
from any instance of a class -- for instance, from within the
|
||||||
|
object itself. The key point is that the "obvious" technique of
|
||||||
|
just returning QSharedPointer<T>(this) can not be used, because
|
||||||
|
this winds up creating multiple distinct QSharedPointer objects
|
||||||
|
with separate reference counts. For this reason you must never
|
||||||
|
create more than one QSharedPointer from the same raw pointer.
|
||||||
|
|
||||||
|
QEnableSharedFromThis defines two member functions called
|
||||||
|
sharedFromThis() that return a QSharedPointer<T> and
|
||||||
|
QSharedPointer<const T>, depending on constness, to \c this:
|
||||||
|
|
||||||
|
\code
|
||||||
|
class Y: public QEnableSharedFromThis<Y>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QSharedPointer<Y> f()
|
||||||
|
{
|
||||||
|
return sharedFromThis();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
QSharedPointer<Y> p(new Y());
|
||||||
|
QSharedPointer<Y> y = p->f();
|
||||||
|
Q_ASSERT(p == y); // p and q must share ownership
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn QSharedPointer::QSharedPointer()
|
\fn QSharedPointer::QSharedPointer()
|
||||||
|
|
||||||
@ -923,6 +960,23 @@
|
|||||||
may have had to the pointer.
|
may have had to the pointer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QSharedPointer<T> QEnableSharedFromThis::sharedFromThis()
|
||||||
|
\since 5.4
|
||||||
|
|
||||||
|
If \c this (that is, the subclass instance invoking this method) is being
|
||||||
|
managed by a QSharedPointer, returns a shared pointer instance pointing to
|
||||||
|
\c this; otherwise returns a QSharedPointer holding a null pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QSharedPointer<const T> QEnableSharedFromThis::sharedFromThis() const
|
||||||
|
\overload
|
||||||
|
\since 5.4
|
||||||
|
|
||||||
|
Const overload of sharedFromThis().
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
|
\fn bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
|
||||||
\relates QSharedPointer
|
\relates QSharedPointer
|
||||||
|
@ -131,6 +131,14 @@ public:
|
|||||||
QSharedPointer<T> lock() const;
|
QSharedPointer<T> lock() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class QEnableSharedFromThis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QSharedPointer<T> sharedFromThis();
|
||||||
|
QSharedPointer<const T> sharedFromThis() const;
|
||||||
|
};
|
||||||
|
|
||||||
template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2);
|
template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2);
|
||||||
template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2);
|
template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2);
|
||||||
template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2);
|
template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2);
|
||||||
|
@ -91,6 +91,7 @@ template<typename T> inline void qt_sharedpointer_cast_check(T *) { }
|
|||||||
//
|
//
|
||||||
template <class T> class QWeakPointer;
|
template <class T> class QWeakPointer;
|
||||||
template <class T> class QSharedPointer;
|
template <class T> class QSharedPointer;
|
||||||
|
template <class T> class QEnableSharedFromThis;
|
||||||
|
|
||||||
class QVariant;
|
class QVariant;
|
||||||
|
|
||||||
@ -479,6 +480,14 @@ private:
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
inline void enableSharedFromThis(const QEnableSharedFromThis<X> *ptr)
|
||||||
|
{
|
||||||
|
ptr->initializeFromSharedPointer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void enableSharedFromThis(...) {}
|
||||||
|
|
||||||
template <typename Deleter>
|
template <typename Deleter>
|
||||||
inline void internalConstruct(T *ptr, Deleter deleter)
|
inline void internalConstruct(T *ptr, Deleter deleter)
|
||||||
{
|
{
|
||||||
@ -499,6 +508,7 @@ private:
|
|||||||
internalSafetyCheckAdd(d, ptr);
|
internalSafetyCheckAdd(d, ptr);
|
||||||
#endif
|
#endif
|
||||||
d->setQObjectShared(ptr, true);
|
d->setQObjectShared(ptr, true);
|
||||||
|
enableSharedFromThis(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X>
|
template <class X>
|
||||||
@ -707,6 +717,37 @@ public:
|
|||||||
T *value;
|
T *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class QEnableSharedFromThis
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
#ifdef Q_COMPILER_DEFAULT_MEMBERS
|
||||||
|
QEnableSharedFromThis() = default;
|
||||||
|
#else
|
||||||
|
Q_DECL_CONSTEXPR QEnableSharedFromThis() {}
|
||||||
|
#endif
|
||||||
|
QEnableSharedFromThis(const QEnableSharedFromThis &) {}
|
||||||
|
QEnableSharedFromThis &operator=(const QEnableSharedFromThis &) { return *this; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline QSharedPointer<T> sharedFromThis() { return QSharedPointer<T>(weakPointer); }
|
||||||
|
inline QSharedPointer<const T> sharedFromThis() const { return QSharedPointer<const T>(weakPointer); }
|
||||||
|
|
||||||
|
#ifndef Q_NO_TEMPLATE_FRIENDS
|
||||||
|
private:
|
||||||
|
template <class X> friend class QSharedPointer;
|
||||||
|
#else
|
||||||
|
public:
|
||||||
|
#endif
|
||||||
|
template <class X>
|
||||||
|
inline void initializeFromSharedPointer(const QSharedPointer<X> &ptr) const
|
||||||
|
{
|
||||||
|
weakPointer = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutable QWeakPointer<T> weakPointer;
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// operator== and operator!=
|
// operator== and operator!=
|
||||||
//
|
//
|
||||||
|
@ -112,6 +112,7 @@ private slots:
|
|||||||
void invalidConstructs();
|
void invalidConstructs();
|
||||||
|
|
||||||
void qvariantCast();
|
void qvariantCast();
|
||||||
|
void sharedFromThis();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void cleanup() { safetyCheck(); }
|
void cleanup() { safetyCheck(); }
|
||||||
@ -2141,6 +2142,228 @@ void tst_QSharedPointer::qvariantCast()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SomeClass : public QEnableSharedFromThis<SomeClass>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SomeClass()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<SomeClass> getSharedPtr()
|
||||||
|
{
|
||||||
|
return sharedFromThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<const SomeClass> getSharedPtr() const
|
||||||
|
{
|
||||||
|
return sharedFromThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
Data data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QSharedPointer::sharedFromThis()
|
||||||
|
{
|
||||||
|
const int generations = Data::generationCounter;
|
||||||
|
const int destructions = Data::destructorCounter;
|
||||||
|
|
||||||
|
{
|
||||||
|
SomeClass sc;
|
||||||
|
QSharedPointer<SomeClass> scp = sc.sharedFromThis();
|
||||||
|
QVERIFY(scp.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 1);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions);
|
||||||
|
|
||||||
|
QSharedPointer<const SomeClass> const_scp = sc.sharedFromThis();
|
||||||
|
QVERIFY(const_scp.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 1);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 1);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const SomeClass sc;
|
||||||
|
QSharedPointer<const SomeClass> const_scp = sc.sharedFromThis();
|
||||||
|
QVERIFY(const_scp.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 2);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 2);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
{
|
||||||
|
SomeClass *sc = new SomeClass;
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
QSharedPointer<SomeClass> scp;
|
||||||
|
QVERIFY(scp.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp = sc->sharedFromThis();
|
||||||
|
QVERIFY(scp.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp = QSharedPointer<SomeClass>(sc);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
QCOMPARE(scp.data(), sc);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
QSharedPointer<SomeClass> scp2;
|
||||||
|
QVERIFY(scp2.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp2 = sc->sharedFromThis();
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(scp2.data(), sc);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
QSharedPointer<const SomeClass> scp3;
|
||||||
|
QVERIFY(scp3.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp3 = sc->sharedFromThis();
|
||||||
|
QVERIFY(!scp3.isNull());
|
||||||
|
QVERIFY(scp == scp3);
|
||||||
|
QVERIFY(scp2 == scp3);
|
||||||
|
QCOMPARE(scp3.data(), sc);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
QSharedPointer<SomeClass> scp4;
|
||||||
|
QVERIFY(scp4.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp4 = sc->getSharedPtr();
|
||||||
|
QVERIFY(!scp4.isNull());
|
||||||
|
QVERIFY(scp == scp4);
|
||||||
|
QVERIFY(scp2 == scp4);
|
||||||
|
QVERIFY(scp3 == scp4);
|
||||||
|
QCOMPARE(scp4.data(), sc);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
QSharedPointer<const SomeClass> scp5;
|
||||||
|
QVERIFY(scp5.isNull());
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
|
||||||
|
scp5 = const_cast<const SomeClass *>(sc)->getSharedPtr();
|
||||||
|
QVERIFY(!scp4.isNull());
|
||||||
|
QVERIFY(scp == scp5);
|
||||||
|
QVERIFY(scp2 == scp5);
|
||||||
|
QVERIFY(scp3 == scp5);
|
||||||
|
QVERIFY(scp4 == scp5);
|
||||||
|
QCOMPARE(scp5.data(), sc);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 3);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
|
||||||
|
QSharedPointer<SomeClass> scp;
|
||||||
|
|
||||||
|
QVERIFY(scp.isNull());
|
||||||
|
|
||||||
|
{
|
||||||
|
QSharedPointer<SomeClass> scp2(new SomeClass());
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
|
||||||
|
scp = scp2->sharedFromThis();
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
{
|
||||||
|
QSharedPointer<const SomeClass> scp2;
|
||||||
|
scp2 = scp->sharedFromThis();
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
{
|
||||||
|
QSharedPointer<SomeClass> scp2;
|
||||||
|
scp2 = scp->getSharedPtr();
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
{
|
||||||
|
QSharedPointer<const SomeClass> scp2;
|
||||||
|
scp2 = qSharedPointerConstCast<const SomeClass>(scp)->getSharedPtr();
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
{
|
||||||
|
QSharedPointer<SomeClass> scp2;
|
||||||
|
scp2 = scp->sharedFromThis();
|
||||||
|
QVERIFY(!scp2.isNull());
|
||||||
|
|
||||||
|
QVERIFY(scp == scp2);
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
|
||||||
|
scp2.clear();
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
QVERIFY(scp2.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 3);
|
||||||
|
QVERIFY(!scp.isNull());
|
||||||
|
|
||||||
|
scp.clear();
|
||||||
|
|
||||||
|
QCOMPARE(Data::generationCounter, generations + 4);
|
||||||
|
QCOMPARE(Data::destructorCounter, destructions + 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace ReentrancyWhileDestructing {
|
namespace ReentrancyWhileDestructing {
|
||||||
struct IB
|
struct IB
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user