Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How do I properly serialize and deserialize a QList class in QT using QDatastream?
Forum Updated to NodeBB v4.3 + New Features

How do I properly serialize and deserialize a QList class in QT using QDatastream?

Scheduled Pinned Locked Moved Solved General and Desktop
29 Posts 5 Posters 7.2k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JonBJ JonB

    @twodee
    You seem to be talking about changing between pointers or not, that's not what I meant. And I trust you used your layer variable and not your Layer type (note the capitalizations, you must get that right, I did mean literally out << 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.

    T Offline
    T Offline
    twodee
    wrote on last edited by
    #5

    @JonB Yes, I did use my layer variable, I did comment out the raster part and that didn't seem to work. My findings look a bit odd to me as well, thanks for trying. :D

    1 Reply Last reply
    1
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #6

      The normal way to do it:

      • create 2 pure virtual protected members in Layer that takes a QDataStream& argument and saves/loads the layer from it
      • create QDataStream stream operators for Layer (not Layer*) 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 as paintWidget owns the allocated memory

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      T 1 Reply Last reply
      3
      • VRoninV VRonin

        The normal way to do it:

        • create 2 pure virtual protected members in Layer that takes a QDataStream& argument and saves/loads the layer from it
        • create QDataStream stream operators for Layer (not Layer*) 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 as paintWidget owns the allocated memory

        T Offline
        T Offline
        twodee
        wrote on last edited by
        #7

        @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 method inline void setName(QString &name) { _name = name; } , what should I be doing in this case?

        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #8

          Looks like you are deserialising on a const method. What is the code around that call?

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          T 2 Replies Last reply
          0
          • VRoninV VRonin

            Looks like you are deserialising on a const method. What is the code around that call?

            T Offline
            T Offline
            twodee
            wrote on last edited by
            #9
            This post is deleted!
            1 Reply Last reply
            0
            • VRoninV VRonin

              Looks like you are deserialising on a const method. What is the code around that call?

              T Offline
              T Offline
              twodee
              wrote on last edited by
              #10

              @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 a QList<Layer*> to be serialized as a whole?

              JonBJ 1 Reply Last reply
              0
              • T twodee

                @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 a QList<Layer*> to be serialized as a whole?

                JonBJ Online
                JonBJ Online
                JonB
                wrote on last edited by JonB
                #11

                @twodee
                Read through threadin this forum https://forum.qt.io/topic/58701/how-to-serialize-deserialize-a-qlist-myclass

                As per http://doc.qt.io/qt-5/datastreamformat.html, QList<T> can be de/serialized. You need to provide the de/serialization for your class T, which is what you have been working on here.

                1 Reply Last reply
                0
                • T Offline
                  T Offline
                  twodee
                  wrote on last edited by
                  #12
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • T Offline
                    T Offline
                    twodee
                    wrote on last edited by twodee
                    #13

                    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.

                    1 Reply Last reply
                    0
                    • VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on last edited by VRonin
                      #14
                      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;
                      }

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      JonBJ T 2 Replies Last reply
                      0
                      • VRoninV VRonin
                        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;
                        }
                        JonBJ Online
                        JonBJ Online
                        JonB
                        wrote on last edited by JonB
                        #15

                        @VRonin
                        I don't want to muddy the waters for the OP here, but may I ask: why do you explicitly serialize the layers 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 own newing? 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 with in >> layers? Or will deserializing never do any newing of elements for you?

                        VRoninV 1 Reply Last reply
                        0
                        • JonBJ JonB

                          @VRonin
                          I don't want to muddy the waters for the OP here, but may I ask: why do you explicitly serialize the layers 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 own newing? 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 with in >> layers? Or will deserializing never do any newing of elements for you?

                          VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on last edited by
                          #16

                          @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?

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          JonBJ 1 Reply Last reply
                          0
                          • VRoninV VRonin

                            @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?
                            JonBJ Online
                            JonBJ Online
                            JonB
                            wrote on last edited by
                            #17

                            @VRonin
                            So are you saying: "Yes, you can de/serialize QList<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 newing is necessary behind the scenes.

                            J.HilkJ 1 Reply Last reply
                            0
                            • JonBJ JonB

                              @VRonin
                              So are you saying: "Yes, you can de/serialize QList<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 newing is necessary behind the scenes.

                              J.HilkJ Offline
                              J.HilkJ Offline
                              J.Hilk
                              Moderators
                              wrote on last edited by
                              #18

                              @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, IIRC

                              Quick google search:
                              https://www.tutorialspoint.com/csharp/csharp_unsafe_codes.htm


                              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                              Q: What's that?
                              A: It's blue light.
                              Q: What does it do?
                              A: It turns blue.

                              JonBJ 1 Reply Last reply
                              0
                              • VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #19

                                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?

                                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                ~Napoleon Bonaparte

                                On a crusade to banish setIndexWidget() from the holy land of Qt

                                1 Reply Last reply
                                0
                                • J.HilkJ J.Hilk

                                  @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, IIRC

                                  Quick google search:
                                  https://www.tutorialspoint.com/csharp/csharp_unsafe_codes.htm

                                  JonBJ Online
                                  JonBJ Online
                                  JonB
                                  wrote on last edited by
                                  #20

                                  @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.

                                  1 Reply Last reply
                                  0
                                  • VRoninV VRonin
                                    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;
                                    }
                                    T Offline
                                    T Offline
                                    twodee
                                    wrote on last edited by
                                    #21

                                    @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;
                                    }
                                    
                                    1 Reply Last reply
                                    0
                                    • VRoninV Offline
                                      VRoninV Offline
                                      VRonin
                                      wrote on last edited by
                                      #22

                                      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

                                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                      ~Napoleon Bonaparte

                                      On a crusade to banish setIndexWidget() from the holy land of Qt

                                      1 Reply Last reply
                                      2
                                      • T Offline
                                        T Offline
                                        twodee
                                        wrote on last edited by
                                        #23

                                        I felt wrong in doing so too as I mentioned in my original question, but I still am not sure where would I be creating the new RasterLayer in my case. Could you give me some clues on how to go about it?

                                        kshegunovK 1 Reply Last reply
                                        0
                                        • VRoninV Offline
                                          VRoninV Offline
                                          VRonin
                                          wrote on last edited by
                                          #24

                                          Memory owned by an object should be created and freed by a method of said object:

                                          You can create a wrapper class around QList<Layer*> that will take care of allocating/freeing the memory inside and create safe datastream operator for this wrapper

                                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                          ~Napoleon Bonaparte

                                          On a crusade to banish setIndexWidget() from the holy land of Qt

                                          T 1 Reply Last reply
                                          2

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved