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. When exactly does QObject::deleteLater() actually delete?
QtWS25 Last Chance

When exactly does QObject::deleteLater() actually delete?

Scheduled Pinned Locked Moved Solved General and Desktop
17 Posts 5 Posters 17.4k 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
    JonB
    wrote on 6 Sept 2018, 12:58 last edited by JonB 9 Jun 2018, 13:00
    #1

    When exactly does QObject::deleteLater() delete/destroy the object? Before anyone is tempted to say "RTFM", please read on....

    For reasons which we really do not want to get into here, I have to create and destroy a dynamic QDialog hundreds (or even thousands) of times in a non-interactive loop. Each time round, the dialog is not shown or exec'ed, rather it just has to be constructed, do some totally non-interactive work, and then be discarded.

    For my sins, I work in Python/PyQt. Python does not have any equivalent of the C++ delete statement (yes, really!). So where you C++-ers would explicitly go delete dialog, I can't.

    Instead, PyQt tells you to use QObject::deleteLater(). Armed with which, I assumed that:

    dialog.deleteLater()
    QApplication.processEvents()
    

    would be equivalent to:

    dialog.destroy()
    

    and (at least effectively) to C++

    delete dialog;
    

    Well, it isn't! What happens with all those deleteLater() + processEvents() is that the dialogs stay around and chomp memory all the while the dialogs are being supposedly created & deleted by my code, only after all my looping is fished do they eventually get destroyed. I cannot have this behaviour here.

    Now, http://doc.qt.io/qt-5/qobject.html#deleteLater states:

    The object will be deleted when control returns to the event loop.
    Note that entering and leaving a new event loop (e.g., by opening a modal dialog) will not perform the deferred deletion; for the object to be deleted, the control must return to the event loop from which deleteLater() was called.

    I am only single-threaded, so that's not an issue. I was under the impression that explicitly calling QApplication.processEvents() was the equivalent of "when control returns to the event loop" above. But it does not seem to be.

    I guess you're going to say: ultimately/originally, the code where you create/delete the dialog must have been called from some "main" event loop. Your own QApplication.processEvents() counts as a different event loop.

    Is that what it's all about? If so, I don't suppose there is any way to ask that main loop to just do its deleting right now, please, without having to actually enter the event dispatcher again?

    If that turns out to be true, I'm going to need some method to actually delete this dialog when I please as I go along. I'm playing with QObject::destroy(). Is this what I can use, given that I cannot go delete? In C++, when you delete and it hits the destructor, apart from the obvious freeing of the C++ memory does it effectively just call destroy?

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 6 Sept 2018, 13:04 last edited by
      #2

      Hi,

      What about the python del statement ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      J 2 Replies Last reply 6 Sept 2018, 13:17
      1
      • V Offline
        V Offline
        VRonin
        wrote on 6 Sept 2018, 13:06 last edited by
        #3

        First thing first. The right thing to do here is to reuse the dialog.
        Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

        Having said that, you can make sure the dialog is destroyed using QEventLoop (i'll use C++, hopefully it's easy to translate this code)

        QEventLoop destroyLoop;
        connect(dialog,&QObject::destroyed,&destroyLoop,&QEventLoop::quit);
        dialog->deleteLater();
        destroyLoop.exec();
        

        "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

        J 2 Replies Last reply 6 Sept 2018, 13:30
        4
        • S SGaist
          6 Sept 2018, 13:04

          Hi,

          What about the python del statement ?

          J Offline
          J Offline
          JonB
          wrote on 6 Sept 2018, 13:17 last edited by
          #4

          @SGaist said in When exactly does QObject::deleteLater() actually delete?:

          What about the python del statement ?

          I will look into that again. However, we are told not to do that (somewhere): it does not delete the object, it decrements a reference count. We are told to use deleteLater instead. I could type more, but I'll have a further investigation...

          1 Reply Last reply
          0
          • V VRonin
            6 Sept 2018, 13:06

            First thing first. The right thing to do here is to reuse the dialog.
            Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

            Having said that, you can make sure the dialog is destroyed using QEventLoop (i'll use C++, hopefully it's easy to translate this code)

            QEventLoop destroyLoop;
            connect(dialog,&QObject::destroyed,&destroyLoop,&QEventLoop::quit);
            dialog->deleteLater();
            destroyLoop.exec();
            
            J Offline
            J Offline
            JonB
            wrote on 6 Sept 2018, 13:30 last edited by JonB 9 Jun 2018, 13:32
            #5

            @VRonin said in When exactly does QObject::deleteLater() actually delete?:

            First thing first. The right thing to do here is to reuse the dialog.
            Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

            Yeah, I wish! If I could, I would :) First problem is there's nowhere for me to keep the dialog handle around, and have it reused by the code. Why? Well the code is low-down in the "back-end". It's just called from a function which wants to "convert HTML to PDF" (ring a bell with you? :) ) Unfortunately, I have to do that via a QWebEnginePage::printToPdf(). But the back-end doesn't know that, or that it needs a dialog and would like to re-use it. And the back-end function is down layers of calls away from the top-level front-end code which could create that dialog and pass its handle around. So problematic for me :(

            Having said that: first I want to sort my existing use of deleteLater not behaving as I expected. Then I can run my app without running out of memory! Then I will indeed look at how hard it would be to re-use that darned dialog!

            Apart from that, could we revisit your code above. (If I understand right) You are saying that QEventLoop::exec() will delete objects marked deleteLater() (which then quits the loop), but QApplication::processEvents() will not? Why? Is it just because your code stays till it comes across that object to destroy, and only then exits the event loop, while the application one only does a few events or something??

            1 Reply Last reply
            0
            • V Offline
              V Offline
              VRonin
              wrote on 6 Sept 2018, 14:08 last edited by
              #6

              One call to processEvents might not be enough to execute the delete if there are pending events to be processed by the item you are trying to delete. I must tap out here though as you need someone way smarter than me to go in the details

              "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

              J 1 Reply Last reply 6 Sept 2018, 14:22
              3
              • V VRonin
                6 Sept 2018, 14:08

                One call to processEvents might not be enough to execute the delete if there are pending events to be processed by the item you are trying to delete. I must tap out here though as you need someone way smarter than me to go in the details

                J Offline
                J Offline
                JonB
                wrote on 6 Sept 2018, 14:22 last edited by
                #7

                @VRonin
                Thanks, that still tells me a lot. I had assumed that one call to QApplication::processEvents() would process all pending events and delete all pending objects to be deleted. The fact that you are indicating this is not necessarily the case is enough to satisfy my question on that!

                G 1 Reply Last reply 6 Sept 2018, 14:57
                0
                • S SGaist
                  6 Sept 2018, 13:04

                  Hi,

                  What about the python del statement ?

                  J Offline
                  J Offline
                  JonB
                  wrote on 6 Sept 2018, 14:53 last edited by
                  #8

                  @SGaist said in When exactly does QObject::deleteLater() actually delete?:

                  What about the python del statement ?

                  For the record: https://stackoverflow.com/a/39255472/489865

                  If you are writing something bulky, you should know that del does not delete the object, it just dereferences it. I.e. variable no longer refers to the place in memory where object data is stored. After that it still needs to be cleaned up by garbage collector in order for memory to be freed (that happens automatically).

                  In Python's reference-count and garbage-collect model, del is not really anything like C++ delete. All it does is decrement a count, e.g.

                  widget = QWidget()
                  something = widget
                  del widget
                  

                  does not delete/destroy/free the QWidget!

                  1 Reply Last reply
                  0
                  • J JonB
                    6 Sept 2018, 14:22

                    @VRonin
                    Thanks, that still tells me a lot. I had assumed that one call to QApplication::processEvents() would process all pending events and delete all pending objects to be deleted. The fact that you are indicating this is not necessarily the case is enough to satisfy my question on that!

                    G Offline
                    G Offline
                    Gojir4
                    wrote on 6 Sept 2018, 14:57 last edited by
                    #9

                    @JonB Hi,

                    Documentation of QEventLoop::ProcessEventsFlag confirms that deleteLater() (DefferedDeleteEvent) is a special case.

                    QEventLoop::AllEvents:
                    All events. Note that DeferredDelete events are processed specially. See QObject::deleteLater() for more details.

                    But it looks like there is now way to really ensure that's object is destroyed.

                    J 1 Reply Last reply 6 Sept 2018, 15:01
                    4
                    • G Gojir4
                      6 Sept 2018, 14:57

                      @JonB Hi,

                      Documentation of QEventLoop::ProcessEventsFlag confirms that deleteLater() (DefferedDeleteEvent) is a special case.

                      QEventLoop::AllEvents:
                      All events. Note that DeferredDelete events are processed specially. See QObject::deleteLater() for more details.

                      But it looks like there is now way to really ensure that's object is destroyed.

                      J Offline
                      J Offline
                      JonB
                      wrote on 6 Sept 2018, 15:01 last edited by
                      #10

                      @Gojir4
                      That is a good reference. The trouble is, I have already quoted from "See QObject::deleteLater() for more details." and (to me) that doesn't explain much better! :)

                      1 Reply Last reply
                      0
                      • V VRonin
                        6 Sept 2018, 13:06

                        First thing first. The right thing to do here is to reuse the dialog.
                        Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

                        Having said that, you can make sure the dialog is destroyed using QEventLoop (i'll use C++, hopefully it's easy to translate this code)

                        QEventLoop destroyLoop;
                        connect(dialog,&QObject::destroyed,&destroyLoop,&QEventLoop::quit);
                        dialog->deleteLater();
                        destroyLoop.exec();
                        
                        J Offline
                        J Offline
                        JonB
                        wrote on 6 Sept 2018, 16:19 last edited by JonB 9 Jun 2018, 16:21
                        #11

                        @VRonin said in When exactly does QObject::deleteLater() actually delete?:

                        First thing first. The right thing to do here is to reuse the dialog.
                        Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

                        Just for the record (because I just know you're interested!). The reason I have to have this UI/dialog is purely to host a QWebEnginePage for printToPdf(). That requires the QWebEnginePage to do two things: the HTML has to be loaded, and then printToPdf() can be called after that (not before) to convert. As you might imagine, the continual recreation & disposal of the dialog we have been talking about is absolutely miniscule compared to these two activities (I think it actually takes longer to finish loading the HTML than to convert it to PDF!). So I could bust my whatevers trying to preserve the dialog as you said, but I think it will make zero difference to my timings, sadly :(

                        J 1 Reply Last reply 7 Sept 2018, 02:10
                        1
                        • J JonB
                          6 Sept 2018, 16:19

                          @VRonin said in When exactly does QObject::deleteLater() actually delete?:

                          First thing first. The right thing to do here is to reuse the dialog.
                          Crate it once, execute 1 cycle of the loop, reset its properties and use it again. Creating and deleting "hundreds (or even thousands)" is incredibly inefficient.

                          Just for the record (because I just know you're interested!). The reason I have to have this UI/dialog is purely to host a QWebEnginePage for printToPdf(). That requires the QWebEnginePage to do two things: the HTML has to be loaded, and then printToPdf() can be called after that (not before) to convert. As you might imagine, the continual recreation & disposal of the dialog we have been talking about is absolutely miniscule compared to these two activities (I think it actually takes longer to finish loading the HTML than to convert it to PDF!). So I could bust my whatevers trying to preserve the dialog as you said, but I think it will make zero difference to my timings, sadly :(

                          J Offline
                          J Offline
                          JKSH
                          Moderators
                          wrote on 7 Sept 2018, 02:10 last edited by JKSH 9 Jul 2018, 02:18
                          #12

                          @JonB said in When exactly does QObject::deleteLater() actually delete?:

                          The reason I have to have this UI/dialog is purely to host a QWebEnginePage for printToPdf(). That requires the QWebEnginePage to do two things: the HTML has to be loaded, and then printToPdf() can be called after that (not before) to convert.

                          There might be better tools for the job. See my post at https://forum.qt.io/topic/94330/generating-pdf-from-html-fast

                          As you might imagine, the continual recreation & disposal of the dialog we have been talking about is absolutely miniscule compared to these two activities (I think it actually takes longer to finish loading the HTML than to convert it to PDF!). So I could bust my whatevers trying to preserve the dialog as you said, but I think it will make zero difference to my timings, sadly :(

                          But your main problem right now is running out of memory, right? If @VRonin's QEventLoop trick doesn't work for whatever reason, re-using the dialog will stop you from getting memory-starved.

                          Another possible workaround: Don't convert all the documents in one large for-loop. Instead, at the end of each conversion, emit a signal or call QMetaObject::invokeMethod() (with Qt::QueuedConnection for both options) to trigger the next conversion. Then, let the function return to the main event loop. This allows QCoreApplication delete your dialog before starting the next conversion.

                          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                          J 1 Reply Last reply 7 Sept 2018, 08:22
                          2
                          • J JKSH
                            7 Sept 2018, 02:10

                            @JonB said in When exactly does QObject::deleteLater() actually delete?:

                            The reason I have to have this UI/dialog is purely to host a QWebEnginePage for printToPdf(). That requires the QWebEnginePage to do two things: the HTML has to be loaded, and then printToPdf() can be called after that (not before) to convert.

                            There might be better tools for the job. See my post at https://forum.qt.io/topic/94330/generating-pdf-from-html-fast

                            As you might imagine, the continual recreation & disposal of the dialog we have been talking about is absolutely miniscule compared to these two activities (I think it actually takes longer to finish loading the HTML than to convert it to PDF!). So I could bust my whatevers trying to preserve the dialog as you said, but I think it will make zero difference to my timings, sadly :(

                            But your main problem right now is running out of memory, right? If @VRonin's QEventLoop trick doesn't work for whatever reason, re-using the dialog will stop you from getting memory-starved.

                            Another possible workaround: Don't convert all the documents in one large for-loop. Instead, at the end of each conversion, emit a signal or call QMetaObject::invokeMethod() (with Qt::QueuedConnection for both options) to trigger the next conversion. Then, let the function return to the main event loop. This allows QCoreApplication delete your dialog before starting the next conversion.

                            J Offline
                            J Offline
                            JonB
                            wrote on 7 Sept 2018, 08:22 last edited by JonB 9 Jul 2018, 08:24
                            #13

                            @JKSH
                            Again, thanks, and I've posted my reason to you in the other thread.

                            To recap: I have now discovered that if I do not use the "recommended" deleteLater() and instead use QDialog::destroy() the memory is freed immediately. I can now process my hundreds/thousands of letters without any memory/resources accumulating till the end, and my most immediate problem of "running the whole machine out of memory" has gone away.

                            I am still investigating how much that actual "dialog create-destroy" is costing. But even though I'm sure it's considerable compared to re-use, it appears that it's actual miniscule compared to loading of the new HTML each time and converting to PDF (it's actually more the HTML load than the PDF convert which costs, perhaps not surprisingly). So re-using the same dialog probably wouldn't save me that much. Now that I have dealt with the memory issue of the repeated dialog I'm in a much happier place!

                            V 1 Reply Last reply 7 Sept 2018, 09:43
                            0
                            • J JonB
                              7 Sept 2018, 08:22

                              @JKSH
                              Again, thanks, and I've posted my reason to you in the other thread.

                              To recap: I have now discovered that if I do not use the "recommended" deleteLater() and instead use QDialog::destroy() the memory is freed immediately. I can now process my hundreds/thousands of letters without any memory/resources accumulating till the end, and my most immediate problem of "running the whole machine out of memory" has gone away.

                              I am still investigating how much that actual "dialog create-destroy" is costing. But even though I'm sure it's considerable compared to re-use, it appears that it's actual miniscule compared to loading of the new HTML each time and converting to PDF (it's actually more the HTML load than the PDF convert which costs, perhaps not surprisingly). So re-using the same dialog probably wouldn't save me that much. Now that I have dealt with the memory issue of the repeated dialog I'm in a much happier place!

                              V Offline
                              V Offline
                              VRonin
                              wrote on 7 Sept 2018, 09:43 last edited by
                              #14

                              @JonB said in When exactly does QObject::deleteLater() actually delete?:

                              use QDialog::destroy()

                              Make sure you are not running into random segfaults due to some thing inside Qt calling a slot of your dialog using Qt::QueuedConnection (or equivalents)

                              "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

                              J 1 Reply Last reply 7 Sept 2018, 09:51
                              2
                              • V VRonin
                                7 Sept 2018, 09:43

                                @JonB said in When exactly does QObject::deleteLater() actually delete?:

                                use QDialog::destroy()

                                Make sure you are not running into random segfaults due to some thing inside Qt calling a slot of your dialog using Qt::QueuedConnection (or equivalents)

                                J Offline
                                J Offline
                                JonB
                                wrote on 7 Sept 2018, 09:51 last edited by
                                #15

                                @VRonin
                                Hmm. I don't know if I know how I would know this?! I don't do anything slot-wise. I create the dialog and get it to load HTML into QWebEnginePage + print to PDF, that finishes synchronously, only then do I destroy the dialog.

                                Does that satisfy you? Or, would you rather I use your earlier deleteLater() + QEventLoop? Would that be safer? I presume that wrt your QueuedConnection this would be just as much of an issue if one used C++ delete as my use of explicit destroy? Or are you saying that delete would deal with this any better than destroy?

                                V J 2 Replies Last reply 7 Sept 2018, 09:57
                                0
                                • J JonB
                                  7 Sept 2018, 09:51

                                  @VRonin
                                  Hmm. I don't know if I know how I would know this?! I don't do anything slot-wise. I create the dialog and get it to load HTML into QWebEnginePage + print to PDF, that finishes synchronously, only then do I destroy the dialog.

                                  Does that satisfy you? Or, would you rather I use your earlier deleteLater() + QEventLoop? Would that be safer? I presume that wrt your QueuedConnection this would be just as much of an issue if one used C++ delete as my use of explicit destroy? Or are you saying that delete would deal with this any better than destroy?

                                  V Offline
                                  V Offline
                                  VRonin
                                  wrote on 7 Sept 2018, 09:57 last edited by
                                  #16

                                  @JonB said in When exactly does QObject::deleteLater() actually delete?:

                                  this would be just as much of an issue if one used C++ delete as my use of explicit destroy? Or are you saying that delete would deal with this any better than destroy?

                                  It is an issue even in C++ using delete indeed, that's the reason why QObject::deleteLater exists

                                  "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
                                  1
                                  • J JonB
                                    7 Sept 2018, 09:51

                                    @VRonin
                                    Hmm. I don't know if I know how I would know this?! I don't do anything slot-wise. I create the dialog and get it to load HTML into QWebEnginePage + print to PDF, that finishes synchronously, only then do I destroy the dialog.

                                    Does that satisfy you? Or, would you rather I use your earlier deleteLater() + QEventLoop? Would that be safer? I presume that wrt your QueuedConnection this would be just as much of an issue if one used C++ delete as my use of explicit destroy? Or are you saying that delete would deal with this any better than destroy?

                                    J Offline
                                    J Offline
                                    JKSH
                                    Moderators
                                    wrote on 7 Sept 2018, 14:25 last edited by
                                    #17

                                    @JonB said in When exactly does QObject::deleteLater() actually delete?:

                                    I don't do anything slot-wise. I create the dialog and get it to load HTML into QWebEnginePage + print to PDF, that finishes synchronously, only then do I destroy the dialog.

                                    If it's fully synchronous and no signals/events touch these objects, then I'd imagine you should be fine.

                                    Just be aware this is a fragile setup -- put big warning comments for yourself (and anyone else who might inherit your code) not to add any event-driven features in this section, or else inexplicable crashes might start occurring.

                                    Or are you saying that delete would deal with this any better than destroy?

                                    Disclaimer: I have never called QWidget::destroy() directly.

                                    To clarify @VRonin's last comment, delete and destroy() have the same brittleness: They introduce the risk of signals/events getting delivered to an object that has already been freed. But if you code carefully, you can create a perfectly functional program with delete/destroy().

                                    When using deleteLater(), we don't have to worry about this risk and can add event-driven features with gay abandon. (In theory, at least. This user doesn't seem to be getting the protection promised by deleteLater(): https://forum.qt.io/topic/93786/events-after-object-destruction Granted, this was back in Qt 4.8.6 so hopefully it's fixed by now)

                                    Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                    1 Reply Last reply
                                    2

                                    8/17

                                    6 Sept 2018, 14:53

                                    • Login

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