Results 1 to 5 of 5

Thread: Serializing QMap<qint8, Claass*> with QDataStream

  1. #1
    Join Date
    Jan 2016
    Location
    Finland
    Posts
    5
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Serializing QMap<qint8, Claass*> with QDataStream

    I have a problem serializing and reading back a QMap that holds a collection of my class called PID.

    In this class I implemented operators << and >> as below, with the help of some good fellas here in this forum.
    Qt Code:
    1. QDataStream &operator <<(QDataStream &out, const PID &pid)
    2. {
    3. out << pid.getKp() << pid.getKi() << pid.getKd();
    4. return out;
    5. }
    6.  
    7.  
    8. QDataStream &operator >>(QDataStream &in, PID *pid)
    9. {
    10. double kp;
    11. double ki;
    12. double kd;
    13. in >> kp >> ki >> kd;
    14. pid = new PID();
    15. pid->setKp(kp);
    16. pid->setKi(ki);
    17. pid->setKd(kd);
    18. return in;
    19. }
    To copy to clipboard, switch view to plain text mode 

    Latter the map is serialized like this
    Qt Code:
    1. PID pid;
    2. pid.setKp(34);
    3. pid.setKi(45);
    4. pid.setKd(54);
    5. QString path = appDir.path() + QDir::separator()
    6. + name + TXT_FILE_EXT;
    7. QFile pidFile(path);
    8. pidFile.open(QIODevice::ReadWrite);
    9. QDataStream stream(&pidFile);
    10. QMap<quint8, PID*> pidList;
    11. stream << pidList;
    12.  
    13. pidList.clear();
    14. stream.device()->reset();
    15.  
    16. stream >> pidList;
    17.  
    18. qDebug() << "Pid map size: " << pidList.size() << " File Size: "<< pidFile.size();
    19. pidFile.close();
    To copy to clipboard, switch view to plain text mode 
    when I run this I get the same "Pid map size: 0 File Size: 8 " even when the map's size is changed in the code. Any Idea how I can get to my goal of serializing the collection of PIDs to a file and read back?
    Thanks.

  2. #2
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Serializing QMap<qint8, Claass*> with QDataStream

    According to QMap's documentation, you can only serialize it to/unserialize it from QDataStream if both key and value types themselves are serializable. The value type of your QMap, PID *, is a plain pointer; I have no idea how it gets serialized to QDataStream, but I doubt it is what you expect (it sure does not call QDataStream &operator <<(QDataStream &out, const PID &pid)). As for deserialization, I can only wonder why the program does not crash randomly when it calls your QDataStream &operator >>(QDataStream &in, PID *pid) on an uninitialized PID *.

    Just think about it for a minute. If your QMap holds PID * values, then I suppose that you allocate PID instances somewhere, then populate the map with pointers to them. In order to deserialize such a map, you would need to allocate PID instances. Your code does not do that.

  3. #3
    Join Date
    Jan 2016
    Location
    Finland
    Posts
    5
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Serializing QMap<qint8, Claass*> with QDataStream

    Thank you yeye_olive.
    I was trying to go with pointers because then otherwise I would have to overload a copy constructor and an assignment operator, and by doing so risk loosing the automatic garbage collection feature that comes with QObject. (but my fear could be void as my understanding of Qt is not that big).

    Anyway I tried to write the operator QDataStream &operator <<(QDataStream &out, const PID &pid) in such manner so it also takes a pointer then at least the written/read types are the same;
    Qt Code:
    1. QDataStream &operator <<(QDataStream &out, const PID *pid)
    2. {
    3. out << pid->getKp() << pid->getKi() << pid->getKd();
    4. return out;
    5. }
    To copy to clipboard, switch view to plain text mode 
    it didn't give an error, and the map size was not zero anymore but the values were one big number that was not the originally saved once.

    So I changed the operators, added a copy constructor and assignment operator to the PID type and now it works like a charm. But I still wonder what would have been the way to go with pointers? is it even possible to do so?
    Qt Code:
    1. PID::PID(const PID &other)
    2. {
    3. kp = other.getKp();
    4. ki = other.getKi();
    5. kd = other.getKd();
    6. }
    7.  
    8. PID &PID::operator=(const PID &other)
    9. {
    10. kp = other.getKp();
    11. ki = other.getKi();
    12. kd = other.getKd();
    13. }
    14.  
    15. QDataStream &operator <<(QDataStream &out, const PID &pid)
    16. {
    17. out << pid.getKp() << pid.getKi() << pid.getKd();
    18. return out;
    19. }
    20.  
    21.  
    22. QDataStream &operator >>(QDataStream &in, PID &pid)
    23. {
    24. double kp;
    25. double ki;
    26. double kd;
    27. in >> kp;
    28. in >> ki;
    29. in >> kd;
    30. pid.setKp(kp);
    31. pid.setKi(ki);
    32. pid.setKd(kd);
    33. return in;
    34. }
    To copy to clipboard, switch view to plain text mode 
    Any suggestion is welcome again.
    I am sure I didn't write the assignment operator and the copy constructor very well and may cause me trouble later on when I try to use them to populate a view.
    Once again thanks.
    Last edited by simex; 8th January 2016 at 22:18.

  4. #4
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Serializing QMap<qint8, Claass*> with QDataStream

    A deserialization operator takes a reference to the object whose value shall be overwritten. For instance your operator:
    Qt Code:
    1. QDataStream &operator >>(QDataStream &in, PID &pid)
    To copy to clipboard, switch view to plain text mode 
    deserializes a PID value and overwrites pid with it.

    With pointers, you would have needed a deserialization operator such as (notice the reference to pointer):
    Qt Code:
    1. QDataStream &operator >>(QDataStream &in, PID *&ppid) {
    2. double kp;
    3. double ki;
    4. double kd;
    5. in >> kp;
    6. in >> ki;
    7. in >> kd;
    8. ppid = new PID(kp, ki, kd);
    9. return in;
    10. }
    To copy to clipboard, switch view to plain text mode 
    but you can see how fragile that would have been:
    • the operator throws away the old value of ppid without calling delete on it first, potentially leaking memory, but it cannot do so because someone may call this operator on an uninitialized PID * (just like we do with double kp, ki, and kd in the code above);
    • the operator allocates a PID, but nothing tracks this allocation; if this operator were to be called in the middle of a complex operation which subsequently throws an exception, chances are that memory would be leaked.


    There is a reason why we do not (de)serialize arbitrary naked pointers: they are just dumb containers for addresses without any enforced semantics for memory allocation and deallocation.

    A much better solution would be to wrap a PID * in a smart pointer class with the desired semantics, and write (de)serialization operators for that class.

    About your PID::operator=(). You forgot a "return *this;". Also, if all your operator does is field-by-field assignment, then you can remove it and leave the compiler generate the same thing by default. Similarly for your copy constructor if it only does field-by-field copy initialization.

  5. The following user says thank you to yeye_olive for this useful post:

    simex (9th January 2016)

  6. #5
    Join Date
    Jan 2016
    Location
    Finland
    Posts
    5
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: Serializing QMap<qint8, Claass*> with QDataStream

    Thank you for breaking down this issues. I'll put this to an effect.

Similar Threads

  1. Replies: 2
    Last Post: 12th December 2013, 14:25
  2. Serializing a Qobject
    By erfan in forum Qt Programming
    Replies: 1
    Last Post: 12th December 2012, 17:00
  3. Serializing QHash to a QByteArray
    By PeterThePuter in forum Qt Programming
    Replies: 3
    Last Post: 17th December 2010, 23:19
  4. Serializing QImage
    By lukass in forum Newbie
    Replies: 1
    Last Post: 26th October 2010, 18:58
  5. Serializing
    By xyzt in forum Qt Programming
    Replies: 1
    Last Post: 23rd March 2008, 08:51

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.