diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2009-05-14 16:30:57 (GMT) |
---|---|---|
committer | Thiago Macieira <thiago.macieira@nokia.com> | 2009-05-18 14:24:02 (GMT) |
commit | d76c5fb7feda66621b435263353f49e9b4b34308 (patch) | |
tree | da4b27c60127d4386abad70c7abc6c7d61539c04 | |
parent | d13162dd4695274dc4bdb286ce85bf198391d94b (diff) | |
download | Qt-d76c5fb7feda66621b435263353f49e9b4b34308.zip Qt-d76c5fb7feda66621b435263353f49e9b4b34308.tar.gz Qt-d76c5fb7feda66621b435263353f49e9b4b34308.tar.bz2 |
Fix handling of dynamic casts in QSharedPointer.
It's wrong to assume that static_cast<> is allowed everywhere where
dynamic_cast<> is allowed. For example, if class C derives from both A
and B, then you can dynamic_cast<B *>(ptr_to_A), but you can't
static_cast.
So introduce a helper for dynamic casts that doesn't do
static_cast.
Reviewed-by: Olivier Goffart
-rw-r--r-- | src/corelib/tools/qsharedpointer_impl.h | 21 | ||||
-rw-r--r-- | tests/auto/qsharedpointer/tst_qsharedpointer.cpp | 137 |
2 files changed, 140 insertions, 18 deletions
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index f1b35ee..ad2d9f2 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -238,6 +238,7 @@ namespace QtSharedPointer { template <class X> friend class ExternalRefCount; template <class X> friend class QWeakPointer; template <class X, class Y> friend QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<Y> &src, X *); + template <class X, class Y> friend QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<Y> &src, X *); template <class X, class Y> friend QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<Y> &src, X *); template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::qStrongRefFromWeakHelper(const QWeakPointer<Y> &src, X *); #endif @@ -509,6 +510,14 @@ namespace QtSharedPointer { return result; } template <class X, class T> + Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<T> &src, X *) + { + QSharedPointer<X> result; + register T *ptr = src.data(); + result.internalSet(src.d, dynamic_cast<X *>(ptr)); + return result; + } + template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<T> &src, X *) { QSharedPointer<X> result; @@ -544,9 +553,7 @@ template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyDynamicCast(src.data(), x)) - return QtSharedPointer::qSharedPointerCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerDynamicCastHelper(src, x); } template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src) @@ -558,17 +565,13 @@ template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyConstCast(src.data(), x)) - return QtSharedPointer::qSharedPointerConstCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerConstCastHelper(src, x); } template <class X, class T> Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src) { X *x = 0; - if (QtSharedPointer::qVerifyConstCast(src.data(), x)) - return QtSharedPointer::qSharedPointerCastHelper(src, x); - return QSharedPointer<X>(); + return QtSharedPointer::qSharedPointerConstCastHelper(src, x); } template <class X, class T> diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index 64439fb..a52bb3e 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -57,8 +57,11 @@ private slots: void downCast(); void upCast(); void differentPointers(); + void virtualBaseDifferentPointers(); #ifndef QTEST_NO_RTTI void dynamicCast(); + void dynamicCastDifferentPointers(); + void dynamicCastVirtualBase(); void dynamicCastFailure(); #endif void customDeleter(); @@ -321,6 +324,10 @@ class DiffPtrDerivedData: public Stuffing, public Data { }; +class VirtualDerived: virtual public Data +{ +}; + void tst_QSharedPointer::downCast() { { @@ -439,7 +446,7 @@ void tst_QSharedPointer::differentPointers() DiffPtrDerivedData *aData = new DiffPtrDerivedData; Data *aBase = aData; Q_ASSERT(aData == aBase); - Q_ASSERT(quintptr(&aData) != quintptr(&aBase)); + Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase)); QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData); QSharedPointer<DiffPtrDerivedData> ptr = qSharedPointerCast<DiffPtrDerivedData>(baseptr); @@ -453,7 +460,7 @@ void tst_QSharedPointer::differentPointers() DiffPtrDerivedData *aData = new DiffPtrDerivedData; Data *aBase = aData; Q_ASSERT(aData == aBase); - Q_ASSERT(quintptr(&aData) != quintptr(&aBase)); + Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase)); QSharedPointer<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData); QSharedPointer<Data> baseptr = ptr; @@ -464,23 +471,53 @@ void tst_QSharedPointer::differentPointers() QVERIFY(baseptr == aData); QVERIFY(baseptr == aBase); } +} + +void tst_QSharedPointer::virtualBaseDifferentPointers() +{ + { + VirtualDerived *aData = new VirtualDerived; + Data *aBase = aData; + Q_ASSERT(aData == aBase); + Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase)); + + QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData); + QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(ptr); + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); + QVERIFY(ptr == aData); + QVERIFY(baseptr == aData); + QVERIFY(baseptr == aBase); + } + + { + VirtualDerived *aData = new VirtualDerived; + Data *aBase = aData; + Q_ASSERT(aData == aBase); + Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase)); - // there is no possibility for different pointers in - // internal reference counting right now - // - // to do that, it's necessary to first implement the ability to - // call (virtual) functions, so that the two differing bases have - // the same reference counter + QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData); + QSharedPointer<Data> baseptr = ptr; + QVERIFY(ptr == baseptr); + QVERIFY(ptr.data() == baseptr.data()); + QVERIFY(ptr == aBase); + QVERIFY(ptr == aData); + QVERIFY(baseptr == aData); + QVERIFY(baseptr == aBase); + } } #ifndef QTEST_NO_RTTI void tst_QSharedPointer::dynamicCast() { - QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData); + DerivedData *aData = new DerivedData; + QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData); { QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(baseptr); QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); @@ -490,6 +527,7 @@ void tst_QSharedPointer::dynamicCast() QWeakPointer<Data> weakptr = baseptr; QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(weakptr); QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); @@ -498,6 +536,87 @@ void tst_QSharedPointer::dynamicCast() { QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>(); QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); +} + +void tst_QSharedPointer::dynamicCastDifferentPointers() +{ + // DiffPtrDerivedData derives from both Data and Stuffing + DiffPtrDerivedData *aData = new DiffPtrDerivedData; + QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData); + + { + QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); + + { + QWeakPointer<Data> weakptr = baseptr; + QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); + + { + QSharedPointer<DiffPtrDerivedData> derivedptr = baseptr.dynamicCast<DiffPtrDerivedData>(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); + + { + Stuffing *nakedptr = dynamic_cast<Stuffing *>(baseptr.data()); + QVERIFY(nakedptr); + + QSharedPointer<Stuffing> otherbaseptr = qSharedPointerDynamicCast<Stuffing>(baseptr); + QVERIFY(!otherbaseptr.isNull()); + QVERIFY(otherbaseptr == nakedptr); + QCOMPARE(otherbaseptr.data(), nakedptr); + QCOMPARE(static_cast<DiffPtrDerivedData*>(otherbaseptr.data()), aData); + } +} + +void tst_QSharedPointer::dynamicCastVirtualBase() +{ + VirtualDerived *aData = new VirtualDerived; + QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData); + + { + QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(baseptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); + + { + QWeakPointer<Data> weakptr = baseptr; + QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(weakptr); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); + QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); + } + QCOMPARE(int(baseptr.d->weakref), 1); + QCOMPARE(int(baseptr.d->strongref), 1); + + { + QSharedPointer<VirtualDerived> derivedptr = baseptr.dynamicCast<VirtualDerived>(); + QVERIFY(baseptr == derivedptr); + QCOMPARE(derivedptr.data(), aData); QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data()); } QCOMPARE(int(baseptr.d->weakref), 1); |