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