Solved 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> Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr) Q_DECLARE_METATYPE(std::shared_ptr<int>); 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; }
-
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.