Nominate our 2022 Qt Champions!

Dragging std::shared_ptr

  • Greetings. I want to use drag-and-drop to drag a QTreeWidgetItem that has std::shared_ptr user data. Qt is throwing an exception because it doesn't know how to store the shared_ptr onto a QDataStream. I read a bit and it seems that Q_DECLARE_SMART_POINTER_METATYPE is supposed to allow this to work. However, I have not had any success. I have built a tiny example showing the problem. Does anyone know how to do this properly?

    In case you're wondering, I need to use shared_ptr (as opposed to other Qt shared pointers) because the pointer comes from a non-Qt part of the application (which I cannot control). I'm not comfortable converting the shared pointer to a raw pointer because it could go out of scope during my operation.

    Thank you.

    // DragSharedPtr.cpp
    #include <QtGlobal>
    #include <QMetaType>
    #include <QVariant>
    #include <QDataStream>
    #include <memory>
    int main()
        qRegisterMetaType< std::shared_ptr<int> >();
        // create variant holding the shared pointer (this works)
        auto spint = std::make_shared<int>(42);
        QVariant varspint = QVariant::fromValue(spint);
        // get the shared pointer back (this works)
        auto spint2 = varspint.value<std::shared_ptr<int>>();
        Q_ASSERT(spint2 == spint);
        // Try to encode the variant into a stream.  This is
        // needed when, for example, dragging the variant.
        // This code compiles, but fails with a console warning:
        //     QVariant::save: unable to save type  
        //                     'std:;shard_ptr<int>' (type id: 1024)
        // and an exception:
        //     Program: <path to Qt>\bin\Qt5Cored.dll
        //     Module: 5.5.1
        //     File: <path to Qt>\src\corelib\global\qglobal.cpp
        //     Line: 2974
        //     ASSERT failure in QVariant::save: "Invalid type to save", 
        //            file <path...>\qvariant.cpp, line 2124
        QByteArray encoded;
        QDataStream stream(&encoded, QIODevice::WriteOnly);
        stream << varspint;
        return 0;

  • Lifetime Qt Champion

    You have to implement QDataStream & QDataStream::operator<<(std::shared_ptr<int>) and QDataStream & QDataStream::operator>>(std::shared_ptr<int>&). I don't see any other possibility, because QDataStream does not know how to serialize/deserialize a std::sgared_ptr.

  • Thanks. Yes, I ended up doing just that. I'm a bit concerned about lifetime of ownership, but I don't see a better way.

Log in to reply