Wrap-Up: Issues with QExplicitlySharedDataPointer (KSharedPtr successor)
Recently, when porting away from KSharedPtr (which is now deprecated under KF5) to QExplicitlySharedDataPointer in KDevelop's frameworks branch, I noticed an interesting issue in the QExplictlySharedDataPointer
API.
Suppose we have two classes both inheriting from QSharedData (directly and indirectly):
class Base : public QSharedData {};
class Derived : public Base {};
Now let's use QExplicitlySharedDataPointer
to manage these shared data objects. And let's write some bogus code on purpose:
QExplicitlySharedDataPointer<Base> base(new Base);
QExplicitlySharedDataPointer<Derived> derived(base); // Oops. That compiles!
Huh? What happened? We now have a shared pointer of type Derived*
pointing to a Base*
object. This is definitely implies wrong usage of the shared pointer type.
The code causing this is easily spotted in qshareddata.h:
template<class X>
inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o)
: d(static_cast<T *>(o.data()))
{
if(d)
d->ref.ref();
}
Wow. There's a static_cast<>
inside one of the constructors of QExplicitlySharedDataPointer
. This cast makes our code compile without any warning/error.
After some discussion with people from the QtCore team we concluded that this is is just wrong and the static_cast<>
shouldn't be there at all. Now in Qt 5.4, this code path is completely disabled thanks to the following patch: https://codereview.qt-project.org/#/c/88569/
Happy porting to QExplicitlySharedDataPointer
again!
Note: QtXmlPatterns is the only Qt module depending on this hidden cast at all. Other modules compile fine without it. This one now needs to define a special macro in order to re-enable the static_cast<>
: QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST