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 can I ensure proper resource management (RAII) when using Qt Plugins?

How can I ensure proper resource management (RAII) when using Qt Plugins?

Scheduled Pinned Locked Moved Solved General and Desktop
pluginsresourcesqt5
7 Posts 3 Posters 5.5k 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.
  • J Offline
    J Offline
    Jakob
    wrote on 17 Dec 2015, 12:52 last edited by
    #1

    My collegue posted the following on StackOverflow:
    http://stackoverflow.com/questions/34312928/qt-object-management-with-qt-plugins

    I suggested to cross-post here, since in this forum the question is more visible to Qt experts. Hopefully I'm right.

    K 1 Reply Last reply 18 Dec 2015, 23:39
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 18 Dec 2015, 21:10 last edited by
      #2

      Hi,

      When you add a widget like he does, he gets back an action. Removing the action from the toolbar and then deleting it should also delete the associated widget.

      Hope it helps

      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
      • J Jakob
        17 Dec 2015, 12:52

        My collegue posted the following on StackOverflow:
        http://stackoverflow.com/questions/34312928/qt-object-management-with-qt-plugins

        I suggested to cross-post here, since in this forum the question is more visible to Qt experts. Hopefully I'm right.

        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 18 Dec 2015, 23:39 last edited by kshegunov
        #3

        @Jakob
        Just deleting the widget doesn't work? In principle Qt handles QObject destruction through signals and slots. For example there is the QObject::destroyed signal that you can subscribe to. This way Qt ensures that at any point if an object is deleted the parent is notified and will remove it from the child list. This technique also resolves the stack vs heap allocation problem. Additionally you can handle QObject pointers through the QPointer class that can be used to safely ascertain that an object does or doesn't exist. QPointer will be automatically set to point to NULL if the QObject it's referencing gets deleted. You could create your widget in your plugin, keep a QPointer to handle it, and when Qt deletes it you'll know, or you could delete it and Qt will know that this was done, because of the destroyed signal. If you're working with the container classes, there is not much of an issue, since they are implicitly shared anyway, and will free the memory when all the referencing objects are freed.

        Kind regards.

        Read and abide by the Qt Code of Conduct

        J 1 Reply Last reply 20 Dec 2015, 09:57
        1
        • K kshegunov
          18 Dec 2015, 23:39

          @Jakob
          Just deleting the widget doesn't work? In principle Qt handles QObject destruction through signals and slots. For example there is the QObject::destroyed signal that you can subscribe to. This way Qt ensures that at any point if an object is deleted the parent is notified and will remove it from the child list. This technique also resolves the stack vs heap allocation problem. Additionally you can handle QObject pointers through the QPointer class that can be used to safely ascertain that an object does or doesn't exist. QPointer will be automatically set to point to NULL if the QObject it's referencing gets deleted. You could create your widget in your plugin, keep a QPointer to handle it, and when Qt deletes it you'll know, or you could delete it and Qt will know that this was done, because of the destroyed signal. If you're working with the container classes, there is not much of an issue, since they are implicitly shared anyway, and will free the memory when all the referencing objects are freed.

          Kind regards.

          J Offline
          J Offline
          Jakob
          wrote on 20 Dec 2015, 09:57 last edited by
          #4

          @kshegunov Thank you for an elaborate answer. Just to make sure I understand correctly what you are saying: even if I only use plain pointers to QObjects all across my code, and also pass these objects as plain pointers to Qt, then still Qt will always know I deleted them and handle this gracefully, because internally all these pointers are wrapped in QPointer?

          Is this guaranteed always to be true? One thing that springs to mind for instance, is how Qt internally also wraps QWidget pointers in a QLayoutItem instance when adding the widget to some layout. Is it true that when I delete the QWidget, automatically the wrapping QLayoutItem is also deleted and the layout is notified?

          K 1 Reply Last reply 20 Dec 2015, 10:48
          0
          • J Jakob
            20 Dec 2015, 09:57

            @kshegunov Thank you for an elaborate answer. Just to make sure I understand correctly what you are saying: even if I only use plain pointers to QObjects all across my code, and also pass these objects as plain pointers to Qt, then still Qt will always know I deleted them and handle this gracefully, because internally all these pointers are wrapped in QPointer?

            Is this guaranteed always to be true? One thing that springs to mind for instance, is how Qt internally also wraps QWidget pointers in a QLayoutItem instance when adding the widget to some layout. Is it true that when I delete the QWidget, automatically the wrapping QLayoutItem is also deleted and the layout is notified?

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 20 Dec 2015, 10:48 last edited by
            #5

            @Jakob

            Just to make sure I understand correctly what you are saying: even if I only use plain pointers to QObjects all across my code, and also pass these objects as plain pointers to Qt, then still Qt will always know I deleted them and handle this gracefully,

            Yes, this is correct.

            because internally all these pointers are wrapped in QPointer?

            No this is not true. Qt's management of objects is pretty involved. The QObject instance is notified by it's children when they are deleted but this is not done by means of QPointer, actually it's not really done through the destroyed signal also. Qt will use the QMetaObject instance attached to each of the QObjects it's handling to do that.

            void QObjectPrivate::setParent_helper(QObject *o)
            {
                Q_Q(QObject);
                if (o == parent)
                    return;
                if (parent) {
                    QObjectPrivate *parentD = parent->d_func();
                    if (parentD->isDeletingChildren && wasDeleted
                        && parentD->currentChildBeingDeleted == q) {
                        // don't do anything since QObjectPrivate::deleteChildren() already
                        // cleared our entry in parentD->children.
                    } else {
                        const int index = parentD->children.indexOf(q);
                        if (parentD->isDeletingChildren) {
                            parentD->children[index] = 0;
                        } else {
                            parentD->children.removeAt(index);
                            if (sendChildEvents && parentD->receiveChildEvents) {
                                QChildEvent e(QEvent::ChildRemoved, q);
                                QCoreApplication::sendEvent(parent, &e);
                            }
                        }
                    }
                }
                parent = o;
                if (parent) {
                    // object hierarchies are constrained to a single thread
                    if (threadData != parent->d_func()->threadData) {
                        qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
                        parent = 0;
                        return;
                    }
                    parent->d_func()->children.append(q);
                    if(sendChildEvents && parent->d_func()->receiveChildEvents) {
                        if (!isWidget) {
                            QChildEvent e(QEvent::ChildAdded, q);
                            QCoreApplication::sendEvent(parent, &e);
                        }
                    }
                }
                if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
                    QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
            }
            

            That is an excerpt from the Qt source relevant to reparenting the QObjects, but how exactly the parent is notified by its children is really beside the point. You only need to know that this is done, and you can safely delete the QObject pointer at any time (even if it's a plain pointer). QPointer is a convenience class for us (user programmers) so we can know when a QObject is deleted (usually by Qt) when we don't own it. Just bear in mind that ownership of objects is weakly defined and is relevant more to the object hierarchy than it is to actual ownership of the objects themselves.

            Is it true that when I delete the QWidget, automatically the wrapping QLayoutItem is also deleted and the layout is notified?

            I can't say for sure that the layout item will be deleted, but the layout holding the widget will be notified and it's going to adjust (sizes) accordingly. I'm pretty sure that if you use QLayout::addWidget to insert your widgets into layouts, the Qt's internal workings will take care of the layout item in case you delete the widget.

            To be very clear, consider the following code:

            int main()
            {
                // ...
               QWidget window;
               QVBoxLayout layout(&window);
               QPushButton button(&window);
               layout.addWidget(&button);
               window.setLayout(&layout);
               window.show();
            
              QApplication::exec();
            }
            

            You see that here the layout and button are created after the widget that contains them, but they're created on the stack. Now consider what will happen if you just simply delete the children in the QWidgets destructor? Obviously you'll run into tons of trouble, because when the stack's unwinding the objects will be freed and then, when the QWidget's destructor executes the layout and button objects will be deleted once again(!), you'll get a nasty segmentation fault. This was the stack vs heap allocation problem I was referring in my previous post. Qt's object management (by notifying the parent for the child's destruction), allows this construct to be valid (and I think better than allocating everything in the heap).

            I hope this clears things up.

            Kind regards.

            Read and abide by the Qt Code of Conduct

            J 1 Reply Last reply 21 Dec 2015, 07:41
            1
            • K kshegunov
              20 Dec 2015, 10:48

              @Jakob

              Just to make sure I understand correctly what you are saying: even if I only use plain pointers to QObjects all across my code, and also pass these objects as plain pointers to Qt, then still Qt will always know I deleted them and handle this gracefully,

              Yes, this is correct.

              because internally all these pointers are wrapped in QPointer?

              No this is not true. Qt's management of objects is pretty involved. The QObject instance is notified by it's children when they are deleted but this is not done by means of QPointer, actually it's not really done through the destroyed signal also. Qt will use the QMetaObject instance attached to each of the QObjects it's handling to do that.

              void QObjectPrivate::setParent_helper(QObject *o)
              {
                  Q_Q(QObject);
                  if (o == parent)
                      return;
                  if (parent) {
                      QObjectPrivate *parentD = parent->d_func();
                      if (parentD->isDeletingChildren && wasDeleted
                          && parentD->currentChildBeingDeleted == q) {
                          // don't do anything since QObjectPrivate::deleteChildren() already
                          // cleared our entry in parentD->children.
                      } else {
                          const int index = parentD->children.indexOf(q);
                          if (parentD->isDeletingChildren) {
                              parentD->children[index] = 0;
                          } else {
                              parentD->children.removeAt(index);
                              if (sendChildEvents && parentD->receiveChildEvents) {
                                  QChildEvent e(QEvent::ChildRemoved, q);
                                  QCoreApplication::sendEvent(parent, &e);
                              }
                          }
                      }
                  }
                  parent = o;
                  if (parent) {
                      // object hierarchies are constrained to a single thread
                      if (threadData != parent->d_func()->threadData) {
                          qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");
                          parent = 0;
                          return;
                      }
                      parent->d_func()->children.append(q);
                      if(sendChildEvents && parent->d_func()->receiveChildEvents) {
                          if (!isWidget) {
                              QChildEvent e(QEvent::ChildAdded, q);
                              QCoreApplication::sendEvent(parent, &e);
                          }
                      }
                  }
                  if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
                      QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
              }
              

              That is an excerpt from the Qt source relevant to reparenting the QObjects, but how exactly the parent is notified by its children is really beside the point. You only need to know that this is done, and you can safely delete the QObject pointer at any time (even if it's a plain pointer). QPointer is a convenience class for us (user programmers) so we can know when a QObject is deleted (usually by Qt) when we don't own it. Just bear in mind that ownership of objects is weakly defined and is relevant more to the object hierarchy than it is to actual ownership of the objects themselves.

              Is it true that when I delete the QWidget, automatically the wrapping QLayoutItem is also deleted and the layout is notified?

              I can't say for sure that the layout item will be deleted, but the layout holding the widget will be notified and it's going to adjust (sizes) accordingly. I'm pretty sure that if you use QLayout::addWidget to insert your widgets into layouts, the Qt's internal workings will take care of the layout item in case you delete the widget.

              To be very clear, consider the following code:

              int main()
              {
                  // ...
                 QWidget window;
                 QVBoxLayout layout(&window);
                 QPushButton button(&window);
                 layout.addWidget(&button);
                 window.setLayout(&layout);
                 window.show();
              
                QApplication::exec();
              }
              

              You see that here the layout and button are created after the widget that contains them, but they're created on the stack. Now consider what will happen if you just simply delete the children in the QWidgets destructor? Obviously you'll run into tons of trouble, because when the stack's unwinding the objects will be freed and then, when the QWidget's destructor executes the layout and button objects will be deleted once again(!), you'll get a nasty segmentation fault. This was the stack vs heap allocation problem I was referring in my previous post. Qt's object management (by notifying the parent for the child's destruction), allows this construct to be valid (and I think better than allocating everything in the heap).

              I hope this clears things up.

              Kind regards.

              J Offline
              J Offline
              Jakob
              wrote on 21 Dec 2015, 07:41 last edited by
              #6

              @kshegunov Loads and loads of gratitude for your elaborate and detailed answer and the effort to look things up. We have certainly gained a lot of new insight now that will help moving forwards. Thanks again!

              K 1 Reply Last reply 21 Dec 2015, 17:56
              0
              • J Jakob
                21 Dec 2015, 07:41

                @kshegunov Loads and loads of gratitude for your elaborate and detailed answer and the effort to look things up. We have certainly gained a lot of new insight now that will help moving forwards. Thanks again!

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 21 Dec 2015, 17:56 last edited by
                #7

                @Jakob

                You're welcome. I was a bit concerned that I'm not making my explanation clear enough, but happily that doesn't seem to be the case. Good luck!

                Kind regards.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                0

                1/7

                17 Dec 2015, 12:52

                • Login

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