Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML object access through model crashes
Forum Updated to NodeBB v4.3 + New Features

QML object access through model crashes

Scheduled Pinned Locked Moved Solved QML and Qt Quick
35 Posts 6 Posters 6.6k 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.
  • kshegunovK kshegunov

    @mzimmers said in QML object access through model crashes:
    Well assuming this is similar to the code we saw above:

    if (listIndex != NgaUI::NOT_IN_LIST)
        return m_list.at(listIndex).get();
    
    auto outcome = std::make_unique<Outcome>(this);
    outcome->setUuid(uuid);
    return m_list.emplaceBack(std::move(outcome)).get();
    

    Or something of this sort, I imagine.

    JoeCFDJ Offline
    JoeCFDJ Offline
    JoeCFD
    wrote on last edited by JoeCFD
    #23

    @kshegunov why is the unique pointer even needed in the first place?
    to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

    kshegunovK mzimmersM GrecKoG 3 Replies Last reply
    0
    • JoeCFDJ JoeCFD

      @kshegunov why is the unique pointer even needed in the first place?
      to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by kshegunov
      #24

      @JoeCFD said in QML object access through model crashes:

      @kshegunov why is the unique pointer even needed in the first place?

      It isn't, strictly speaking. If it were me, I'd've implemented it with regular ol' raw pointers. The difference is only in the semantics - std::unique_ptr means "I own the stuff" (also implying you can't have two different std::unique_ptr instances pointing to the same object, hence the copy constructor being deleted).

      to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

      Both the model and the Outcome class are derived from Qt classes. I imagine the OutcomeModel is derived from QAbstractTableModel, where as the Outcome is derived from QObject (or something akin).

      Read and abide by the Qt Code of Conduct

      JoeCFDJ 1 Reply Last reply
      0
      • JoeCFDJ JoeCFD

        @kshegunov why is the unique pointer even needed in the first place?
        to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

        mzimmersM Offline
        mzimmersM Offline
        mzimmers
        wrote on last edited by
        #25

        @JoeCFD said in QML object access through model crashes:

        is OutcomeModel a subclass of Qt class?

        Yes, a subclass of QAbstractListModel. And Outcome is a subclass of QObject.

        1 Reply Last reply
        0
        • kshegunovK kshegunov

          @JoeCFD said in QML object access through model crashes:

          @kshegunov why is the unique pointer even needed in the first place?

          It isn't, strictly speaking. If it were me, I'd've implemented it with regular ol' raw pointers. The difference is only in the semantics - std::unique_ptr means "I own the stuff" (also implying you can't have two different std::unique_ptr instances pointing to the same object, hence the copy constructor being deleted).

          to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

          Both the model and the Outcome class are derived from Qt classes. I imagine the OutcomeModel is derived from QAbstractTableModel, where as the Outcome is derived from QObject (or something akin).

          JoeCFDJ Offline
          JoeCFDJ Offline
          JoeCFD
          wrote on last edited by JoeCFD
          #26

          @kshegunov Ok. Qt has its own garbage collection mechanism. Therefore, any derived classes from Qt classes may not need any shared or unique pointers unless they are needed to be deleted immediately for example inside one func call(sometimes I do it). I guess in most cases, raw pointers are good enough while Qt will take care of memory release.
          In his case, the pointer is used(returned). I guess a raw pointer is good enough.

          1 Reply Last reply
          0
          • JoeCFDJ JoeCFD

            @kshegunov why is the unique pointer even needed in the first place?
            to @mzimmers: is OutcomeModel a subclass of Qt class? I can not see it.

            GrecKoG Offline
            GrecKoG Offline
            GrecKo
            Qt Champions 2018
            wrote on last edited by
            #27

            @JoeCFD the advantage of using an owning smart pointer in a container is that when removing an element from a container, the pointed-to object will be automatically deleted.

            @mzimmers the question is now why are you using this getOutcome() function at all in your model?

            How do you expose the uuid in the first place? Do you get it from your OutcomeList? Can't you directly add a role returning an Outcome*?

            JoeCFDJ mzimmersM 2 Replies Last reply
            0
            • GrecKoG GrecKo

              @JoeCFD the advantage of using an owning smart pointer in a container is that when removing an element from a container, the pointed-to object will be automatically deleted.

              @mzimmers the question is now why are you using this getOutcome() function at all in your model?

              How do you expose the uuid in the first place? Do you get it from your OutcomeList? Can't you directly add a role returning an Outcome*?

              JoeCFDJ Offline
              JoeCFDJ Offline
              JoeCFD
              wrote on last edited by JoeCFD
              #28

              @GrecKo That is ok. This case is same as I do in a func call. But, I do not think his usage of shared or unique pointer in this func is correct.

              raw pointers will work for mzimmers as well. He got confused with shared or unique pointers.

              1 Reply Last reply
              0
              • GrecKoG GrecKo

                @JoeCFD the advantage of using an owning smart pointer in a container is that when removing an element from a container, the pointed-to object will be automatically deleted.

                @mzimmers the question is now why are you using this getOutcome() function at all in your model?

                How do you expose the uuid in the first place? Do you get it from your OutcomeList? Can't you directly add a role returning an Outcome*?

                mzimmersM Offline
                mzimmersM Offline
                mzimmers
                wrote on last edited by mzimmers
                #29

                @GrecKo I'll do my best to explain this briefly yet clearly.

                My app has several models. One model is the SpaceModel. The SpaceModel contains a list of Space objects. Each Space contains a list of Outcome UUIDs, which reference items in the OutcomeModel.

                I did this because both Spaces and Outcomes are distinct, independent entities in my system (neither "owns" the other), and this was the best I could think of.

                So, the getOutcome() is to give the Space objects visibility into the Outcome properties.

                I have no doubt there's a better way to do this, but this was the best I could come up with.

                GrecKoG 1 Reply Last reply
                0
                • mzimmersM mzimmers

                  @GrecKo I'll do my best to explain this briefly yet clearly.

                  My app has several models. One model is the SpaceModel. The SpaceModel contains a list of Space objects. Each Space contains a list of Outcome UUIDs, which reference items in the OutcomeModel.

                  I did this because both Spaces and Outcomes are distinct, independent entities in my system (neither "owns" the other), and this was the best I could think of.

                  So, the getOutcome() is to give the Space objects visibility into the Outcome properties.

                  I have no doubt there's a better way to do this, but this was the best I could come up with.

                  GrecKoG Offline
                  GrecKoG Offline
                  GrecKo
                  Qt Champions 2018
                  wrote on last edited by
                  #30

                  @mzimmers alright, that seems sensible enough.

                  @JoeCFD said in QML object access through model crashes:

                  @GrecKo That is ok. This case is same as I do in a func call. But, I do not think his usage of shared or unique pointer in this func is correct.
                  raw pointers will work for mzimmers as well. He got confused with shared or unique pointers.

                  I didn't understand what you mean.
                  If the OutcomeModel class actually owns the Outcome instances, using a container with owning smart pointers looks correct to me.

                  mzimmersM 1 Reply Last reply
                  0
                  • mzimmersM mzimmers has marked this topic as solved on
                  • mzimmersM mzimmers has marked this topic as unsolved on
                  • GrecKoG GrecKo

                    @mzimmers alright, that seems sensible enough.

                    @JoeCFD said in QML object access through model crashes:

                    @GrecKo That is ok. This case is same as I do in a func call. But, I do not think his usage of shared or unique pointer in this func is correct.
                    raw pointers will work for mzimmers as well. He got confused with shared or unique pointers.

                    I didn't understand what you mean.
                    If the OutcomeModel class actually owns the Outcome instances, using a container with owning smart pointers looks correct to me.

                    mzimmersM Offline
                    mzimmersM Offline
                    mzimmers
                    wrote on last edited by
                    #31

                    Hi all -

                    Sorry, but I have to re-open this; problem still exists after all.

                    Summary (as brief as I can make it):

                    I have a model for a class I've defined:

                    class Outcome : public QObject
                    {
                        Q_OBJECT
                        QML_ELEMENT
                    
                    typedef std::shared_ptr<Outcome> OutcomePtr;
                    typedef QList<OutcomePtr> OutcomeList;
                    
                    class OutcomeModel : public QAbstractListModel
                    {
                        Q_OBJECT
                        QML_ELEMENT
                    
                        Outcome *getOutcome(const QUuid &uuid)
                        {
                            const auto i { getIndex(uuid) };
                            if (i == NgaUI::NOT_IN_LIST) {
                                return nullptr;
                            } else {
                                return m_list.at(i).get();
                            }
                        }
                    

                    These outcome objects have a N:N relation with another class Space. I maintain the relations in a list in my Space class:

                    class Space : public QObject {
                        Q_OBJECT
                        QML_ELEMENT
                        QList<QUuid> m_outcomeList;
                        Q_PROPERTY(QList<QUuid> outcomeList READ outcomeList WRITE setOutcomeList NOTIFY outcomeListChanged FINAL)
                        // all the stuff for above Q_PROPERTY is defined and seems to work.
                    

                    The size of m_outcomeList can be from 0 to arbitrarily large. (I also have a Space model.)

                    In QML, I have a Space detail card with the following:

                    Pane {
                        id: spaceDetail
                        property Space space
                        property var outcomeList: space.outcomeList
                        ListView {
                            model: spaceDetail.outcomeList
                            delegate: outcomeComponent
                            Component {
                                id: outcomeComponent
                                RowLayout {
                                    property Outcome outcome: outcomeModel.getOutcome(modelData)
                                    Label {
                                        text: outcome !== null ? outcome.name : "no name available"
                                    }
                                    // and so on.
                    

                    When I navigate to a space detail for a space that has a non-0 outcome list, everything works fine. When I then navigate to another space detail, two bad things happen:

                    1. the Outcome destructor is invoked for a valid outcome (should not be invoked)
                    2. the program crashes after a few seconds. The stack pointer points to stuff within my destructor (which does nothing other than a qDebug().
                      Screenshot 2024-02-26 154139.png

                    I have tried this with smart pointers and raw pointers, with the same result.

                    I know this is a lot to digest, but...can anyone see ANYTHING wrong with what I'm doing?

                    GrecKoG 1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      Hi all -

                      Sorry, but I have to re-open this; problem still exists after all.

                      Summary (as brief as I can make it):

                      I have a model for a class I've defined:

                      class Outcome : public QObject
                      {
                          Q_OBJECT
                          QML_ELEMENT
                      
                      typedef std::shared_ptr<Outcome> OutcomePtr;
                      typedef QList<OutcomePtr> OutcomeList;
                      
                      class OutcomeModel : public QAbstractListModel
                      {
                          Q_OBJECT
                          QML_ELEMENT
                      
                          Outcome *getOutcome(const QUuid &uuid)
                          {
                              const auto i { getIndex(uuid) };
                              if (i == NgaUI::NOT_IN_LIST) {
                                  return nullptr;
                              } else {
                                  return m_list.at(i).get();
                              }
                          }
                      

                      These outcome objects have a N:N relation with another class Space. I maintain the relations in a list in my Space class:

                      class Space : public QObject {
                          Q_OBJECT
                          QML_ELEMENT
                          QList<QUuid> m_outcomeList;
                          Q_PROPERTY(QList<QUuid> outcomeList READ outcomeList WRITE setOutcomeList NOTIFY outcomeListChanged FINAL)
                          // all the stuff for above Q_PROPERTY is defined and seems to work.
                      

                      The size of m_outcomeList can be from 0 to arbitrarily large. (I also have a Space model.)

                      In QML, I have a Space detail card with the following:

                      Pane {
                          id: spaceDetail
                          property Space space
                          property var outcomeList: space.outcomeList
                          ListView {
                              model: spaceDetail.outcomeList
                              delegate: outcomeComponent
                              Component {
                                  id: outcomeComponent
                                  RowLayout {
                                      property Outcome outcome: outcomeModel.getOutcome(modelData)
                                      Label {
                                          text: outcome !== null ? outcome.name : "no name available"
                                      }
                                      // and so on.
                      

                      When I navigate to a space detail for a space that has a non-0 outcome list, everything works fine. When I then navigate to another space detail, two bad things happen:

                      1. the Outcome destructor is invoked for a valid outcome (should not be invoked)
                      2. the program crashes after a few seconds. The stack pointer points to stuff within my destructor (which does nothing other than a qDebug().
                        Screenshot 2024-02-26 154139.png

                      I have tried this with smart pointers and raw pointers, with the same result.

                      I know this is a lot to digest, but...can anyone see ANYTHING wrong with what I'm doing?

                      GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote on last edited by
                      #32

                      @mzimmers it appears you have an ownership problem.

                      Who owns the std::shared_ptr<Outcome> in OutcomeModel and who are they shared with? Do they have a QObject parent?

                      mzimmersM 1 Reply Last reply
                      1
                      • GrecKoG GrecKo

                        @mzimmers it appears you have an ownership problem.

                        Who owns the std::shared_ptr<Outcome> in OutcomeModel and who are they shared with? Do they have a QObject parent?

                        mzimmersM Offline
                        mzimmersM Offline
                        mzimmers
                        wrote on last edited by mzimmers
                        #33

                        @GrecKo from my updateModel() function:

                        std::shared_ptr<Outcome> pOutcome = nullptr;
                        
                        // determine whether the outcome in this message already exists in list.
                        const auto listIndex { getIndex(uuid) };
                        if (listIndex == NgaUI::NOT_IN_LIST) { // will append to list below.
                            pOutcome = std::make_shared<Outcome>(this);
                        } else {
                            pOutcome = m_list.at(listIndex);
                        }
                        ...
                        if (listIndex == NgaUI::NOT_IN_LIST) {
                            beginInsertRows(QModelIndex(), m_list.size(),  m_list.size());
                            m_list.append(pOutcome);
                            endInsertRows();
                        

                        EDIT:

                        Regarding who they're shared with, I do create an instance in QML, using my getOutcome() function, but this works with a raw pointer, so I don't think it's sharing the smart pointer, right?

                        GrecKoG 1 Reply Last reply
                        0
                        • mzimmersM mzimmers

                          @GrecKo from my updateModel() function:

                          std::shared_ptr<Outcome> pOutcome = nullptr;
                          
                          // determine whether the outcome in this message already exists in list.
                          const auto listIndex { getIndex(uuid) };
                          if (listIndex == NgaUI::NOT_IN_LIST) { // will append to list below.
                              pOutcome = std::make_shared<Outcome>(this);
                          } else {
                              pOutcome = m_list.at(listIndex);
                          }
                          ...
                          if (listIndex == NgaUI::NOT_IN_LIST) {
                              beginInsertRows(QModelIndex(), m_list.size(),  m_list.size());
                              m_list.append(pOutcome);
                              endInsertRows();
                          

                          EDIT:

                          Regarding who they're shared with, I do create an instance in QML, using my getOutcome() function, but this works with a raw pointer, so I don't think it's sharing the smart pointer, right?

                          GrecKoG Offline
                          GrecKoG Offline
                          GrecKo
                          Qt Champions 2018
                          wrote on last edited by
                          #34

                          @mzimmers Does the Outcome constructor set a QObject parent? By calling the base constructor QObject(parent) or with an explicit call to QObject::setParent.

                          mzimmersM 1 Reply Last reply
                          2
                          • GrecKoG GrecKo

                            @mzimmers Does the Outcome constructor set a QObject parent? By calling the base constructor QObject(parent) or with an explicit call to QObject::setParent.

                            mzimmersM Offline
                            mzimmersM Offline
                            mzimmers
                            wrote on last edited by mzimmers
                            #35

                            @GrecKo it does now.

                            And that seems to have fixed the problem.

                            Before your post:

                            Outcome::Outcome(QObject *parent)
                            {}
                            

                            now:

                            Outcome::Outcome(QObject *parent) : QObject(parent)
                            {}
                            

                            I'm no longer hitting the destructor, and no crashes.

                            @GrecKo I have no idea how you thought of that, but thank you very much.

                            EDIT: I'm still doing something not quite right -- now, when I close my application (using the "X" in the window title bar), I then get the destroyed messages, and my program reports as crashed after a few seconds. This I can live with, though I'd like to find the cause.

                            1 Reply Last reply
                            0
                            • mzimmersM mzimmers has marked this topic as solved on

                            • Login

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