Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-111940

Leak: SwipeDelegate components don't get destroyed, even after the QQmlEngine is destroyed

    XMLWordPrintable

Details

    Description

      Code

      cppobj.h

      #ifndef CPPOBJ_H
      #define CPPOBJ_H
      
      #include <QObject>
      #include <QQmlEngine>
      #include <QSet>
      #include <QDebug>
      
      class CppObj;
      extern QSet<CppObj*> globalObjectRegistry;
      
      class CppObj : public QObject {
          Q_OBJECT
          QML_ELEMENT
      
      public:
          explicit CppObj(QObject *parent = nullptr) : QObject{parent}
          {
              qDebug() << "Constructing" << this;
              globalObjectRegistry << this;
          }
      
          ~CppObj()
          {
              qDebug() << "Deleting" << this << "with parent" << parent();
              globalObjectRegistry.remove(this);
          }
      };
      
      #endif // CPPOBJ_H
      

      main.cpp

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include "cppobj.h"
      
      QSet<CppObj*> globalObjectRegistry;
      
      int main(int argc, char *argv[])
      {
          QGuiApplication app(argc, argv);
      
          int returnValue;
          {
              QQmlApplicationEngine engine(QUrl("qrc:/main.qml"));
              returnValue = app.exec();
          }
          qDebug("=== QQmlApplicationEngine has been destroyed ===");
      
          if (globalObjectRegistry.isEmpty())
              qDebug("All CppObjs were deleted at shutdown");
          else
              qDebug() << "These CppObjs were not deleted at shutdown:" << globalObjectRegistry;
      
          return returnValue;
      }
      

      main.qml

      import QtQuick 2.15
      import QtQuick.Window 2.15
      import QtQuick.Controls 2.15
      import MyCppModule 1.0
      
      Window {
          width: 640
          height: 480
          visible: true
      
          ListView {
              anchors.fill: parent
      
              model: ListModel {
                  ListElement { name: "Swipe left" }
              }
      
              delegate: SwipeDelegate {
                  id: dg
                  width: 640
                  Component.onCompleted: console.log(`Created ${dg}`)
                  Component.onDestruction: console.log(`Destroying ${dg}`)
      
                  swipe.right: Text {
                      id: innerText
                      anchors.right: parent.right
                      text: "Close the app and check the output"
                      Component.onCompleted: console.log(`Created inner ${innerText}`)
                      Component.onDestruction: console.log(`Destroying inner ${innerText}`)
      
                      // The QML engine will report that this object gets destroyed, but its C++'s destructor won't get called
                      CppObj {
                          id: innerObj
                          Component.onCompleted: console.log(`Created inner ${innerObj}`)
                          Component.onDestruction: console.log(`Destroying inner ${innerObj}`)
                      }
                  }
      
                  Text {
                      id: outerText
                      text: name
                      Component.onCompleted: console.log(`Created outer ${outerText}`)
                      Component.onDestruction: console.log(`Destroying outer ${outerText}`)
      
                      // This object will get destroyed properly
                      CppObj {
                          id: outerObj
                          Component.onCompleted: console.log(`Created outer ${outerObj}`)
                          Component.onDestruction: console.log(`Destroying outer ${outerObj}`)
                      }
                  }
              }
          }
      }
      

       

      Steps to reproduce

      1. Build and run the attached project
      2. Swipe the text from the right
      3. Close the window

       

      Debug output

      At startup:

      Constructing CppObj(0x1e6bdb98160)
      qml: Created SwipeDelegate_QMLTYPE_1(0x1e6bd8c66b0)
      qml: Created outer QQuickText(0x1e6bda642d0)
      qml: Created outer CppObj(0x1e6bdb98160)
      

      After swiping:

      Constructing CppObj(0x1e6bdc68800)
      qml: Created inner QQuickText(0x1e6bdc47470)
      qml: Created inner CppObj(0x1e6bdc68800)
      

      After closing window:

      qml: Destroying outer CppObj(0x1e6bdb98160)
      qml: Destroying outer QQuickText(0x1e6bda642d0)
      qml: Destroying inner CppObj(0x1e6bdc68800)
      qml: Destroying inner QQuickText(0x1e6bdc47470)
      qml: Destroying SwipeDelegate_QMLTYPE_1(0x1e6bd8c66b0)
      Deleting CppObj(0x1e6bdb98160) with parent QObject(0x1e6bda642d0)
      === QQmlApplicationEngine has been destroyed ===
      These CppObjs were not deleted at shutdown: QSet(CppObj(0x1e6bdc68800))
      

       

      Observations

      • The QML engine reports that the inner object is getting destroyed, but its C++'s destructor is never called
      • In contrast, the outer object's C++ destructor does get called while the QML engine is shutting down

      Attachments

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            skoh-qt Sze Howe Koh
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: