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. [solved] Serialize heap objects pointed to by QList
QtWS25 Last Chance

[solved] Serialize heap objects pointed to by QList

Scheduled Pinned Locked Moved General and Desktop
qlistserialization
15 Posts 3 Posters 6.0k Views
  • 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.
  • SGaistS Offline
    SGaistS Offline
    SGaist
    Lifetime Qt Champion
    wrote on last edited by
    #6

    Did you consider Qt's implicit sharing helper classes ?

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #7

      As @SGaist said in the first response you just need to provide the operator>> for the pointer. The syntax is not obvious but it's quite logical when you see it. Here's an example:

      struct Foo {
          Foo(const QString& foo = QString()) : data(foo) {}
          QString data;
      };
      
      QDataStream& operator<<(QDataStream& out, const Foo* foo) { out << foo->data; return out;  }
      QDataStream& operator>>(QDataStream& in, Foo*& foo) { foo = new Foo(); in >> foo->data; return in;  }
      //yes, that's a reference to a pointer ;)
      

      and then...

      QByteArray storage;
      
      QList<Foo*> orig { new Foo("bar"), new Foo("bazz") };
      QDataStream storeStream(&storage, QIODevice::WriteOnly);
      storeStream << orig;
      qDeleteAll(orig);
      
      QList<Foo*> retr;
      QDataStream retrStream(&storage, QIODevice::ReadOnly);
      retrStream >> retr;
      qDeleteAll(retr);
      
      1 Reply Last reply
      2
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #8

        Hi guys! Thanks for your replies,
        @SGaist : No, I wasn't aware of that feature. Will check it out!
        @Chris-Kawa : Sounds aweseommely simple, but doesn't this contradict Samuel's former statment: "You have to [...] handle the creation of the objects yourself" ?
        I'm talking about the part:
        QList<Foo*> retr;
        QDataStream retrStream(&storage, QIODevice::ReadOnly);
        retrStream >> retr; -> does Qt call my constructor for every object in the list here?
        qDeleteAll(retr);
        Cheers,
        Kalsan

        Chris KawaC 1 Reply Last reply
        0
        • ? A Former User

          Hi guys! Thanks for your replies,
          @SGaist : No, I wasn't aware of that feature. Will check it out!
          @Chris-Kawa : Sounds aweseommely simple, but doesn't this contradict Samuel's former statment: "You have to [...] handle the creation of the objects yourself" ?
          I'm talking about the part:
          QList<Foo*> retr;
          QDataStream retrStream(&storage, QIODevice::ReadOnly);
          retrStream >> retr; -> does Qt call my constructor for every object in the list here?
          qDeleteAll(retr);
          Cheers,
          Kalsan

          Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #9

          @kalsan said:

          Sounds aweseommely simple, but doesn't this contradict Samuel's former statment: "You have to [...] handle the creation of the objects yourself" ?

          No. I am handling it myself by calling new Foo() in the operator>>.

          There's no magic here. When Qt deserializes a list it resizes it to the size value stored in the data and initializes each of its element by calling operator>> on it. In this case the element type happens to be a pointer, but it's exactly the same as if it were an int or a QString. We need to initialize the variable in any case and in case of a pointer we do it by assigning a new Foo() to it and filling its data from the stream.

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #10

            To answer your question specifically - no, it does not call a constructor for your objects. It calls a (default) constructor for a pointer to your object.
            In pseudocode something like this:

            stream >> typeid;
            if(typeid == a_type_id_of_a_list) {
                stream >> sizeOfTheList
                QList<Type> list;
                for(int i=0; i<sizeOfTheList; ++i ) {
                    Type variable; //creates a default constructed value of Type
                    stream >> variable;
                    list << variable;
                }
            }
            

            The important thing to notice is that the Type in this case is Foo*, a pointer. If it were Foo then it would default construct Foo object, but here all it does is default construct a pointer, which simply creates a null pointer. Then an operator>> is called and the pointer variable is passed to it by reference and we initialize it.

            1 Reply Last reply
            1
            • ? Offline
              ? Offline
              A Former User
              wrote on last edited by
              #11

              Hey Chris,
              So I spend hours trying to understand why the hell the code I generated from what I learned from you and the Qt documentation wouldn't even compile. The answer is simple: Deserializing QString works fine, but if I try to do that with a qint32... BAM!
              So the Qt documentation for QDataStream says, tralala (yes, I AM slowly getting nuts with this), just go QString str; qint32 a; in >> str >> a; So far for the expectation.
              Now, let's talk about reality. Please change in your Foo example the type of data from QString to qint32.
              This is what I am getting (and no, even throwing the computer out of the window and picking it up 4200 floors beyond didn't help):
              -> Error: invalid conversion from 'qint32 {aka int}' to 'UnitStruct*' [-fpermissive] QDataStream& operator>>(QDataStream& in, UnitStruct*& foo) { foo = new UnitStruct(); in >> foo->data; return in; } ^
              -> note: initializing argument 2 of 'QDataStream& operator>>(QDataStream&, UnitStruct*&)' QDataStream& operator>>(QDataStream& in, UnitStruct*& foo) { foo = new UnitStruct(); in >> foo->data; return in; } ^
              -> Error: cannot bind rvalue '(UnitStruct*)((long int)foo->UnitStruct::data)' to 'UnitStruct*&' QDataStream& operator>>(QDataStream& in, UnitStruct*& foo) { foo = new UnitStruct(); in >> foo->data; return in; } ^
              By experience, I know I can be veeeery slow to get things. So please pardon me if I, once again, don't see the huge bar right in front of my head, but I am completely hopeless about this right now.
              Thanks for your patience...
              Kalsan

              1 Reply Last reply
              0
              • Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by Chris Kawa
                #12

                Yup, works just as well:

                struct UnitStruct {
                    UnitStruct(qint32 foo = 0) : data(foo) {}
                    qint32 data;
                };
                
                QDataStream& operator<<(QDataStream& out, const UnitStruct* foo) { out << foo->data; return out;  }
                QDataStream& operator>>(QDataStream& in, UnitStruct*& foo) { foo = new UnitStruct(); in >> foo->data; return in;  }
                
                QByteArray storage;
                
                QList<UnitStruct*> orig { new UnitStruct(42), new UnitStruct(66) };
                QDataStream storeStream(&storage, QIODevice::WriteOnly);
                storeStream << orig;
                qDeleteAll(orig);
                
                QList<UnitStruct*> retr;
                QDataStream retrStream(&storage, QIODevice::ReadOnly);
                retrStream >> retr;
                qDeleteAll(retr);
                
                1 Reply Last reply
                0
                • ? Offline
                  ? Offline
                  A Former User
                  wrote on last edited by
                  #13

                  Well I seriously wonder if I might have a corrupt Qt version or something... I copy-pasted the first 6 lines of your code above (up to an without QByteArray storate;) and I get the three compile errors I pasted above. I did clean and rebuild the entire project.
                  I'm using unpatched (direct from repo) Qt 5.4.1-9 with Qt Creator on Arch Linux, default gcc configuration.
                  Looks to me like the exact same code will compile on your machine but not on mine. Should I consider filing a bug report?
                  Cheers,
                  Kalsan

                  1 Reply Last reply
                  0
                  • Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by Chris Kawa
                    #14

                    Should I consider filing a bug report?

                    You might, but I'm not sure to whom exactly. This doesn't look like a Qt bug. More like a compiler one. What version of gcc are you using? I don't have a linux to test this but it works fine on both VS2013 and MinGW 4.9.1(which is basically gcc).

                    Oh, and btw.
                    Error: invalid conversion from 'qint32 {aka int}' to 'UnitStruct*'
                    This looks like the wrong thing is passed to the operator>>. Are you sure you didn't by mistake try to read the data into QList<qint32> instead of QList<UnitStruct*>?

                    1 Reply Last reply
                    0
                    • ? Offline
                      ? Offline
                      A Former User
                      wrote on last edited by
                      #15

                      I couldn't quite believe that this could be an actual bug, so I kept testing.
                      And the result... oh well... I'm truly ashamed... I have included QDataStream in every file... except the one I actually tested.
                      So the solution is: #include <QDataStream> Facepalm
                      Thanks for your tips, I'm now gonna implement what you told me.

                      1 Reply Last reply
                      0

                      • Login

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