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. QDataStream with vector of pointers
QtWS25 Last Chance

QDataStream with vector of pointers

Scheduled Pinned Locked Moved Solved General and Desktop
15 Posts 3 Posters 3.2k 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.
  • V Offline
    V Offline
    VincentLiu
    wrote on last edited by VincentLiu
    #1

    Hi, I am using QDataStream for serialization. I want to use a base class CommandObj and two derived classes AoiCommandObj and CurrentCommandObj in a QVector. That's why I use pointer of CommandObj for polymorphism instead of simple CommandObj instances. Is it right ???

    This is my class LightObj:

    #ifndef LIGHTOBJ_H
    #define LIGHTOBJ_H
    
    #include <commandobj.h>
    #include <QObject>
    #include <QVector>
    #include <QDateTime>
    
    using namespace std;
    
    class LightObj
    {
    public:
        LightObj();
    
        ~LightObj();
    
        void setCommandObjs(const QVector<CommandObj*>& commandObjs);
        QVector<CommandObj*> getCommandObjs() const;
    
    private:
    
        QVector<CommandObj*> _commandObjs;
    };
    
    QDataStream &operator<<(QDataStream &out, const LightObj &lightObj);
    QDataStream &operator>>(QDataStream &in, LightObj &lightObj);
    

    Below is my base class CommonObj.h and .cpp in the QVector:

    #ifndef COMMANDOBJ_H
    #define COMMANDOBJ_H
    
    #include <QObject>
    #include <QDataStream>
    #include <QDebug>
    
    using namespace std;
    
    class CommandObj
    {
    public:
    
        CommandObj();
        ~CommandObj();
    
        void setCommandName(const QString& commandName);
        QString getCommandName() const;
    
    private:
    
        QString _commandName;
    
    };
    
    QDataStream &operator<<(QDataStream &out, const CommandObj *commandObj);
    QDataStream &operator>>(QDataStream &in, CommandObj *commandObj);
    
    

    and the CommonObj.cpp:

    #include "commandobj.h"
    
    CommandObj::CommandObj()
    {
    
    }
    
    CommandObj::~CommandObj()
    {
    
    }
    
    void CommandObj::setCommandName(const QString& commandName)
    {
        this->_commandName = commandName;
    }
    
    QString CommandObj::getCommandName() const
    {
        return this->_commandName;
    }
    
    QDataStream &operator<<(QDataStream &out, const CommandObj *commandObj)
    {
        out << commandObj->getCommandName()
    
        return out;
    }
    
    QDataStream &operator>>(QDataStream &in, CommandObj *commandObj)
    {
        qInfo() << "QDataStream &operator>>(QDataStream &in, CommandObj *commandObj)";
    
        QString commandName;
    
        in >> commandName;
    
        commandObj->setCommandName(commandName);
        
        return in;
    }
    
    

    Where I do my serialization

        LightObj lightObj;
    
        lightObj.setCommandObjs(_commandObjs);
    
        QFile configFile("ac.dat");
    
        if (configFile.open(QIODevice::WriteOnly))
        {
            QDataStream out(&configFile);
    
            out << lightObj;
        }
    
        configFile.close();
    

    The above serialization seems correct without errors. However, I bumped into an segmentation fault while doing deserialization:

     QFile configFile("ac.dat");
    
        if (configFile.open(QIODevice::ReadOnly))
        {
            QDataStream configDataStream(&configFile);
    
            configDataStream >> _standardLightObj;
    
        }
        else
        {
            emit loadConfigFailSignal(fileName);
        }
    
        configFile.close();
    

    The error happens at the following line in CommandObj.cpp:

    void CommandObj::setCommandName(const QString& commandName)
    {
        this->_commandName = commandName;
    }
    

    I have no idea about the segmentation fault, did I make any mistake in this architecture? Please help, thanks

    jsulmJ 1 Reply Last reply
    0
    • V VincentLiu

      Hi, I am using QDataStream for serialization. I want to use a base class CommandObj and two derived classes AoiCommandObj and CurrentCommandObj in a QVector. That's why I use pointer of CommandObj for polymorphism instead of simple CommandObj instances. Is it right ???

      This is my class LightObj:

      #ifndef LIGHTOBJ_H
      #define LIGHTOBJ_H
      
      #include <commandobj.h>
      #include <QObject>
      #include <QVector>
      #include <QDateTime>
      
      using namespace std;
      
      class LightObj
      {
      public:
          LightObj();
      
          ~LightObj();
      
          void setCommandObjs(const QVector<CommandObj*>& commandObjs);
          QVector<CommandObj*> getCommandObjs() const;
      
      private:
      
          QVector<CommandObj*> _commandObjs;
      };
      
      QDataStream &operator<<(QDataStream &out, const LightObj &lightObj);
      QDataStream &operator>>(QDataStream &in, LightObj &lightObj);
      

      Below is my base class CommonObj.h and .cpp in the QVector:

      #ifndef COMMANDOBJ_H
      #define COMMANDOBJ_H
      
      #include <QObject>
      #include <QDataStream>
      #include <QDebug>
      
      using namespace std;
      
      class CommandObj
      {
      public:
      
          CommandObj();
          ~CommandObj();
      
          void setCommandName(const QString& commandName);
          QString getCommandName() const;
      
      private:
      
          QString _commandName;
      
      };
      
      QDataStream &operator<<(QDataStream &out, const CommandObj *commandObj);
      QDataStream &operator>>(QDataStream &in, CommandObj *commandObj);
      
      

      and the CommonObj.cpp:

      #include "commandobj.h"
      
      CommandObj::CommandObj()
      {
      
      }
      
      CommandObj::~CommandObj()
      {
      
      }
      
      void CommandObj::setCommandName(const QString& commandName)
      {
          this->_commandName = commandName;
      }
      
      QString CommandObj::getCommandName() const
      {
          return this->_commandName;
      }
      
      QDataStream &operator<<(QDataStream &out, const CommandObj *commandObj)
      {
          out << commandObj->getCommandName()
      
          return out;
      }
      
      QDataStream &operator>>(QDataStream &in, CommandObj *commandObj)
      {
          qInfo() << "QDataStream &operator>>(QDataStream &in, CommandObj *commandObj)";
      
          QString commandName;
      
          in >> commandName;
      
          commandObj->setCommandName(commandName);
          
          return in;
      }
      
      

      Where I do my serialization

          LightObj lightObj;
      
          lightObj.setCommandObjs(_commandObjs);
      
          QFile configFile("ac.dat");
      
          if (configFile.open(QIODevice::WriteOnly))
          {
              QDataStream out(&configFile);
      
              out << lightObj;
          }
      
          configFile.close();
      

      The above serialization seems correct without errors. However, I bumped into an segmentation fault while doing deserialization:

       QFile configFile("ac.dat");
      
          if (configFile.open(QIODevice::ReadOnly))
          {
              QDataStream configDataStream(&configFile);
      
              configDataStream >> _standardLightObj;
      
          }
          else
          {
              emit loadConfigFailSignal(fileName);
          }
      
          configFile.close();
      

      The error happens at the following line in CommandObj.cpp:

      void CommandObj::setCommandName(const QString& commandName)
      {
          this->_commandName = commandName;
      }
      

      I have no idea about the segmentation fault, did I make any mistake in this architecture? Please help, thanks

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by jsulm
      #2

      @VincentLiu You mean you get segmentation fault in this line?

      this->_commandName = commandName;
      

      What is _standardLightObj? And was it initialized before doing "configDataStream >> _standardLightObj;"?
      It is a pointer, right? Did you assign it a pointer to an CommandObj instance?

      You should actually use references:

      QDataStream &operator>>(QDataStream &in, CommandObj &commandObj)
      

      Note: "this->" is not needed (C++ is not Python :-)).

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      V 1 Reply Last reply
      1
      • jsulmJ jsulm

        @VincentLiu You mean you get segmentation fault in this line?

        this->_commandName = commandName;
        

        What is _standardLightObj? And was it initialized before doing "configDataStream >> _standardLightObj;"?
        It is a pointer, right? Did you assign it a pointer to an CommandObj instance?

        You should actually use references:

        QDataStream &operator>>(QDataStream &in, CommandObj &commandObj)
        

        Note: "this->" is not needed (C++ is not Python :-)).

        V Offline
        V Offline
        VincentLiu
        wrote on last edited by
        #3

        @jsulm Hi, thanks for your reply,

        Yes, I get segmentation fault in this line:

        this->_commandName = commandName;
        

        I declare the _standardLightObj in a header without using pointer :

        LightObj _standardLightObj;
        

        Am I wrong???

        I create the QVector<CommandObj*> like this:

        QVector<CommandObj*> commandObjs;
        
        CommandObj *commandObj = new CommandObj();
        CommandObj *aoiCommandObj = new AoiCommandObj();
        CommandObj *currentCommandObj = new CurrentCommandObj();
        
        commandObjs.push_back(commandObj);
        commandObjs.push_back(aoiCommandObj);
        commandObjs.push_back(currentCommandObj);
        

        I should use the pointer of CommanObj for the polymorphism, right ?
        If so, can I still use the reference form ????

        QDataStream &operator>>(QDataStream &in, CommandObj &commandObj)
        

        Thanks~~~

        jsulmJ 1 Reply Last reply
        0
        • V VincentLiu

          @jsulm Hi, thanks for your reply,

          Yes, I get segmentation fault in this line:

          this->_commandName = commandName;
          

          I declare the _standardLightObj in a header without using pointer :

          LightObj _standardLightObj;
          

          Am I wrong???

          I create the QVector<CommandObj*> like this:

          QVector<CommandObj*> commandObjs;
          
          CommandObj *commandObj = new CommandObj();
          CommandObj *aoiCommandObj = new AoiCommandObj();
          CommandObj *currentCommandObj = new CurrentCommandObj();
          
          commandObjs.push_back(commandObj);
          commandObjs.push_back(aoiCommandObj);
          commandObjs.push_back(currentCommandObj);
          

          I should use the pointer of CommanObj for the polymorphism, right ?
          If so, can I still use the reference form ????

          QDataStream &operator>>(QDataStream &in, CommandObj &commandObj)
          

          Thanks~~~

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @VincentLiu You can use polymorphism with references as well, but if you put pointers in a vector then you can still use pointers.

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          V 1 Reply Last reply
          0
          • jsulmJ jsulm

            @VincentLiu You can use polymorphism with references as well, but if you put pointers in a vector then you can still use pointers.

            V Offline
            V Offline
            VincentLiu
            wrote on last edited by
            #5

            @jsulm How about the declaration of LightObj _standardLightObj? Is it correct? Any thing strange you found in my work ?

            jsulmJ 1 Reply Last reply
            0
            • V VincentLiu

              @jsulm How about the declaration of LightObj _standardLightObj? Is it correct? Any thing strange you found in my work ?

              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @VincentLiu said in QDataStream with vector of pointers:

              LightObj _standardLightObj

              I don't see how it could be incorrect except that you seem to use a global variable which is bad.
              Did you try to debug as I suggested before?

              https://forum.qt.io/topic/113070/qt-code-of-conduct

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

                Your problem, almost surely comes from commandObj->setCommandName(commandName); with commandObj being null or dangling.

                A few things:

                • Could you show us the implementation of QDataStream &operator<<(QDataStream &out, const LightObj &lightObj); and QDataStream &operator>>(QDataStream &in, LightObj &lightObj); ? (i'm 99.99% sure the problem is here)
                • if AoiCommandObj and CurrentCommandObj have different members to serialise you'll need a more general approach.
                • make sure you have clear the concept of virtual

                The usual approach in this case is declare two virtual protected methods in the base class to do the serialisation. something like

                class CommandObj{
                // other stuff
                protected:
                virtual void serialise(QDataStream& stream) const {stream << _commandName;}
                virtual void deserialise(QDataStream& stream) {stream >> _commandName;}
                firend QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                firend QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                };
                QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                

                and in the definition:

                QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj){commandObj.serialise(out); return out;}
                QDataStream &operator>>(QDataStream &in, CommandObj& commandObj){commandObj.deserialise(in); return in;}
                

                now in the classes derived from CommandObj you just need to override serialise and deserialise to make everything work

                "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

                V 1 Reply Last reply
                1
                • VRoninV VRonin

                  Your problem, almost surely comes from commandObj->setCommandName(commandName); with commandObj being null or dangling.

                  A few things:

                  • Could you show us the implementation of QDataStream &operator<<(QDataStream &out, const LightObj &lightObj); and QDataStream &operator>>(QDataStream &in, LightObj &lightObj); ? (i'm 99.99% sure the problem is here)
                  • if AoiCommandObj and CurrentCommandObj have different members to serialise you'll need a more general approach.
                  • make sure you have clear the concept of virtual

                  The usual approach in this case is declare two virtual protected methods in the base class to do the serialisation. something like

                  class CommandObj{
                  // other stuff
                  protected:
                  virtual void serialise(QDataStream& stream) const {stream << _commandName;}
                  virtual void deserialise(QDataStream& stream) {stream >> _commandName;}
                  firend QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                  firend QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                  };
                  QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                  QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                  

                  and in the definition:

                  QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj){commandObj.serialise(out); return out;}
                  QDataStream &operator>>(QDataStream &in, CommandObj& commandObj){commandObj.deserialise(in); return in;}
                  

                  now in the classes derived from CommandObj you just need to override serialise and deserialise to make everything work

                  V Offline
                  V Offline
                  VincentLiu
                  wrote on last edited by VincentLiu
                  #8

                  @VRonin Thanks. You are right. The commandObj is not accessible in commandObj->setCommandName(commandName); when I am under debug mode.

                  Here is my implementation:

                  QDataStream &operator<<(QDataStream &out, const LightObj &lightObj)
                  {
                      out<< lightObj.getCommandObjs();
                      return out;
                  }
                  
                  QDataStream &operator>>(QDataStream &in, LightObj &lightObj)
                  {
                      QVector<CommandObj*> commandObjs;
                  
                      in >>  commandObjs;
                  
                      lightObj.setCommandObjs(commandObjs);
                  
                      return in;
                  }
                  

                  I am trying your suggestion now~~~

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

                    Bingo!

                    The language/library is not as smart as you think it is. even if out<< lightObj.getCommandObjs(); might be smart enough to serialise pointers correctly when you use in >> commandObjs; how can the system know how much memory to allocate and whether a CommandObj* in the vector is a AoiCommandObj or a CurrentCommandObj?

                    You just need to do more manual work

                    "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

                    V 1 Reply Last reply
                    2
                    • V VincentLiu

                      @VRonin Thanks. You are right. The commandObj is not accessible in commandObj->setCommandName(commandName); when I am under debug mode.

                      Here is my implementation:

                      QDataStream &operator<<(QDataStream &out, const LightObj &lightObj)
                      {
                          out<< lightObj.getCommandObjs();
                          return out;
                      }
                      
                      QDataStream &operator>>(QDataStream &in, LightObj &lightObj)
                      {
                          QVector<CommandObj*> commandObjs;
                      
                          in >>  commandObjs;
                      
                          lightObj.setCommandObjs(commandObjs);
                      
                          return in;
                      }
                      

                      I am trying your suggestion now~~~

                      jsulmJ Offline
                      jsulmJ Offline
                      jsulm
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @VincentLiu

                      QVector<CommandObj*> commandObjs;
                      
                          in >>  commandObjs;
                      

                      Your vector contains pointers and nobody creates instances as far as I can see. You need to read in a loop something like:

                      while(...) {
                          CommandObj* commandObj = new CommandObj();
                          in>>commandObj;
                          commandObjs.append(&commandObj);
                      }
                      

                      https://forum.qt.io/topic/113070/qt-code-of-conduct

                      V 1 Reply Last reply
                      0
                      • jsulmJ jsulm

                        @VincentLiu

                        QVector<CommandObj*> commandObjs;
                        
                            in >>  commandObjs;
                        

                        Your vector contains pointers and nobody creates instances as far as I can see. You need to read in a loop something like:

                        while(...) {
                            CommandObj* commandObj = new CommandObj();
                            in>>commandObj;
                            commandObjs.append(&commandObj);
                        }
                        
                        V Offline
                        V Offline
                        VincentLiu
                        wrote on last edited by
                        #11

                        @jsulm Hi, how can I know the condition should be in while loop ??? I don't have other informations

                        1 Reply Last reply
                        0
                        • VRoninV VRonin

                          Bingo!

                          The language/library is not as smart as you think it is. even if out<< lightObj.getCommandObjs(); might be smart enough to serialise pointers correctly when you use in >> commandObjs; how can the system know how much memory to allocate and whether a CommandObj* in the vector is a AoiCommandObj or a CurrentCommandObj?

                          You just need to do more manual work

                          V Offline
                          V Offline
                          VincentLiu
                          wrote on last edited by
                          #12

                          @VRonin Hi, I got your points. What is the 'manual work' your mentioned?

                          jsulmJ VRoninV 2 Replies Last reply
                          0
                          • V VincentLiu

                            @VRonin Hi, I got your points. What is the 'manual work' your mentioned?

                            jsulmJ Offline
                            jsulmJ Offline
                            jsulm
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @VincentLiu While serializing you will need to write type information for each object, so later, when you're de-serializing you know what you're going to read next.
                            Serializing:

                            1. Write type information (could be just a byte)
                            2. Write object

                            De-serializing:

                            1. Read type information
                            2. Depending on the type create a CommandObj, AoiCommandObj or a CurrentCommandObj object
                            3. Read the object
                            while( !in.atEnd())...
                            

                            https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply
                            1
                            • V VincentLiu

                              @VRonin Hi, I got your points. What is the 'manual work' your mentioned?

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

                              @VincentLiu

                              class CommandObj{
                              public:
                              enum CommandIDs : qint8 {
                              cmdInvalid
                              ,cmdAoiCommand
                              ,cmdCurrentCommand
                              };
                              CommandObj()
                              :classID(cmdInvalid)
                              {}
                              virtual  ~CommandObj()=default; //you probably want a virtual destructor too
                              void setCommandName(const QString& commandName);
                              QString getCommandName() const;
                              qint8 getClassID() const {return classID;}
                              protected:
                              QString _commandName;
                              const qint8 classID; // use this to identify AoiCommandObj from CurrentCommandObj, set it in the constructor
                              virtual void serialise(QDataStream& stream) const {stream << _commandName;}
                              virtual void deserialise(QDataStream& stream) {stream >> _commandName;}
                              firend QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                              firend QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                              };
                              QDataStream &operator<<(QDataStream &out, const CommandObj& commandObj);
                              QDataStream &operator>>(QDataStream &in, CommandObj& commandObj);
                              
                              QDataStream &operator<<(QDataStream &out, const LightObj &lightObj)
                              {
                              const QVector<CommandObj*> allCmds=lightObj.getCommandObjs();
                                  out<< static_cast<qint32>(allCmds.size());
                              for(CommandObj* cmd : allCmds)
                              out<< cmd->getClassID() << *cmd;
                                  return out;
                              }
                              
                              QDataStream &operator>>(QDataStream &in, LightObj &lightObj)
                              {
                              qint32 vecSize=0;
                                in >>vecSize;
                              qint8 cmdType=CommandObj::cmdInvalid;
                                  QVector<CommandObj*> commandObjs;
                              for(int i=0;i<vecSize;++i){
                                in >>cmdType;
                              CommandObj* tempObj = nullptr;
                              switch(cmdType){
                              case CommandObj::cmdAoiCommand:
                              tempObj =new AoiCommandObj;
                              break;
                              case CommandObj::cmdCurrentCommand:
                              tempObj = new CurrentCommandObj;
                              break;
                              default:
                              Q_ASSERT_X(false,"QDataStream &operator>>(QDataStream &in, LightObj &lightObj)","Trying to load unsupported command");
                              }
                              if(!tempObj) continue;
                              in >> *tempObj;
                              commandObjs << tempObj;
                              }
                                  lightObj.setCommandObjs(commandObjs);
                              
                                  return in;
                              }
                              

                              "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
                              3
                              • V Offline
                                V Offline
                                VincentLiu
                                wrote on last edited by
                                #15

                                @VRonin and @jsulm

                                Finally it works!!!!!
                                Really thanks for your patience and kindness.

                                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