Solved How do I properly serialize and deserialize a QList class in QT using QDatastream?
-
@JonB said in How do I properly serialize and deserialize a QList class in QT using QDatastream?:
You might like to check this. If I'm right, you won't be able to use anything in that approach in the way you thought it worked. And if I'm wrong you can tell me so!
Hi, thanks for your input. I tried this out and for some reason, if I directly use
Layer
nothing gets serialized (maybe a NULL value does) and none of the data gets written to the file. I have tried this earlier on, but gave it a try again swapping the datatypes of the overloaded operator fromRasterLayer
withLayer*
, but it still doesn't seem to do the trick. I was hoping it would, but I think I am missing something here. -
@twodee
You seem to be talking about changing between pointers or not, that's not what I meant. And I trust you used yourlayer
variable and not yourLayer
type (note the capitalizations, you must get that right, I did mean literallyout << layer;
). I'm surprised at your finding as now I don't understand how the cast could make any difference at runtime, but I'm not a C++ expert so we'll leave it at that. Sorry. -
@JonB Yes, I did use my
layer
variable, I did comment out theraster
part and that didn't seem to work. My findings look a bit odd to me as well, thanks for trying. :D -
The normal way to do it:
- create 2 pure virtual protected members in
Layer
that takes aQDataStream&
argument and saves/loads the layer from it - create
QDataStream
stream operators forLayer
(notLayer*
) that do nothing but calling those protected methods - serialise something that will tell you what kind of Layer it will be (something like
QVariant::userType
does) - serialise directly by dereferencing a
Layer*
no need to cast anything
RasterLayer *layer2 = new RasterLayer; in >> *layer2;
is perfectly valid, as long aspaintWidget
owns the allocated memory - create 2 pure virtual protected members in
-
@VRonin Hi, thanks for responding. I am getting this error which I usually can avoid using a
const
somewhere:error: passing ‘const RasterLayer’ as ‘this’ argument discards qualifiers [-fpermissive]
:setName(name);
As you can see in the
layer.h
, it is an inline methodinline void setName(QString &name) { _name = name; }
, what should I be doing in this case? -
Looks like you are deserialising on a const method. What is the code around that call?
-
This post is deleted! -
@VRonin I figured the serialization out, now I have to do something like
out << *layer;
to get it serialized. But how will that allow me to serialize aQList<Layer*>
to be serialized as a whole? -
@twodee
Read through threadin this forum https://forum.qt.io/topic/58701/how-to-serialize-deserialize-a-qlist-myclassAs per http://doc.qt.io/qt-5/datastreamformat.html,
QList<T>
can be de/serialized. You need to provide the de/serialization for your classT
, which is what you have been working on here. -
This post is deleted! -
As the post said it's about one line with the operator new, could you tell me what that line is?
QList<Layer*> layers = paintWidget->getItems(); out << layers;
This doesn't seem to do the trick. I have been scratching my head for too long, sorry if I am being stupid.
Also for some reason overloading
QDataStream& operator<<(QDataStream& ds, const Layer *layer)
doesn't work anymore, which did work earlier. -
out << qint32(layers.size()); for(Layer* layer : qAsConst(layers)) out << qint32(layer->type()) << *layer;
qint32 size; qint32 type; in >> size; while(size-- >0 ){ in >> type; Layer* layer = nullptr; switch(type){ case Raster: layer = new RasterLayer; break; default: Q_UNREACHABLE(); } in >> *layer; }
-
@VRonin
I don't want to muddy the waters for the OP here, but may I ask: why do you explicitly serialize thelayers
list yourself in a loop? I thought that the point of the link I mentioned, http://doc.qt.io/qt-5/datastreamformat.html, is that it shows:The QDataStream allows you to serialize some of the Qt data types. The table below lists the data types that QDataStream can serialize
QList<T> The number of items (quint32) The items (T)
so why can't you just
out << layers
?Is this because you want to know where
layer->type()
is in the serialization, so that you can look at it during deserialization and do your ownnew
ing? If there were no sub-classing going on in the list elements then you wouldn't need to do that and could just do the list directly? Could it then just be deserialized within >> layers
? Or will deserializing never do anynew
ing of elements for you? -
@JonB That would imply having datastream operators acting on pointers and that's dangerous:
- What if you pass a null pointer
- What if you pass a dangling pointer
- Who own the memory allocated by the pointer? the operator?
-
@VRonin
So are you saying: "Yes, you can de/serializeQList<T>
directly as per that link, but while that's fine for simple types it's not suitable for pointers"?I may be confusing myself. In my C# we don't have "pointers" and we just de/serialize lists directly without a care. Deserializing does whatever
new
ing is necessary behind the scenes. -
@JonB said in How do I properly serialize and deserialize a QList class in QT using QDatastream?:
I may be confusing myself. In my C# we don't have "pointers" and we just de/serialize lists directly without a care.
I beg to differ!
you can use pointers in c# and manage your memory by hand, but you have to explicitly tell the compiler to allow it with
-unsafe
, IIRCQuick google search:
https://www.tutorialspoint.com/csharp/csharp_unsafe_codes.htm -
take this example:
// QList<int*> m_ownerList; m_ownerList.append(new int(5)); m_ownerList.append(new int(3));
m_myInt1 = new int(5); m_myInt2 = new int(3); m_nonOwnerList = QList<int*>{{m_myInt1 ,m_myInt2} };
What should
QDataStream& operator>>(QDataStream& , const QList<int*> )
do? free the memory already allocated or not? -
@J.Hilk
But I would never want to use pointers in C# or manage memory by hand, that's (more than) half the point of using C#!?Maybe there's a misunderstanding. I don't use C# with Qt (I use Python). I'm just familiar with C# compared to C++. I am trying to understand @VRonin's explanation of de/serializing this
QList<T>
, where he is saying he does it explicitly to manage pointers, when I know I would just de/serialize a list from C# without iterating the elements myself, and trying to understand why. -
@VRonin Hi, thanks for the extended example. I have come up with a working solutin that looks similar to yours, could you let me know if this is a good way to deal with it?
QDataStream& operator >>(QDataStream& stream, QList<Layer*>& layers){ layers.clear(); int size; int type; stream>>size; QString name; QPixmap pixmap; Layer* layer = nullptr; for(int i =0; i<size; ++i){ stream >> name >> type; switch (type) { case Layer::RASTER: stream >> pixmap; layer = new RasterLayer(name, pixmap.toImage()); break; default: Q_UNREACHABLE(); break; } layer->read(stream); layers.push_back(layer); } return stream; }
-
The very first line of your code is a memory leak. This is exactly my point. Don't handle memory inside serialising/deserialising it's not the right place