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. Deleting a shared object
Forum Updated to NodeBB v4.3 + New Features

Deleting a shared object

Scheduled Pinned Locked Moved Solved General and Desktop
21 Posts 4 Posters 2.4k Views 3 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.
  • D Offline
    D Offline
    deisik
    wrote on 15 Oct 2023, 16:49 last edited by deisik
    #1

    What is the canonical way (if there is any) of deleting a shared object, that is, an object shared across an arbitrary number of threads (more than two), to avoid potential heap corruption (use after free)?

    For example, in a non-GUI thread I create an object which is then shown via QTableView (GUI) and independently processed in yet another thread. How can I safely dispose of it when it is no longer needed (which is determined programmatically by the first thread where the object originates), and all the other threads should discard it, with the last (first?) thread in the object propagation chain deleting this object?

    Right now, the last thread to receive the deletion signal (passed on by the processing thread) deletes the object (in my case, it's GUI). But there might be better (simpler) ways to accomplish this

    1 Reply Last reply
    0
    • D deisik
      16 Oct 2023, 18:54

      @SGaist said in Deleting a shared object:

      @deisik yes. Otherwise it's your job to delete the QSharedPointer object at the correct time.

      Gotcha

      D Offline
      D Offline
      deisik
      wrote on 19 Oct 2023, 12:45 last edited by deisik
      #18

      So I tried to use a QSharedPointer, and it didn't make sense. I have only 3 threads and easily over 1M data objects. In this case specifically, using a QSharedPointer for each of these data objects is a huge overkill incurring as much overhead, both in terms of effort to code and the CPU cycles to run this code – the code to handle the stack of the QSharedPointer pointers themselves (which includes tracking and deleting them)

      Instead, I just emit the queued deletion signal from the first thread (where the data object is created) to the second (where the data is actually used, as designed), and the second thread then passes it on after processing to the third (GUI) where the object is deleted in a deterministic, thread-safe manner, with no memory footprint and virtually no extra execution time (compared to keeping track and managing 1M of QSharedPointer instances). Simple, safe and efficient

      Indeed, when it becomes a matter of dozens or even hundreds of threads, the QSharedPointer may be a viable and in many cases probably the best solution (I'm far from there yet), but not in the case where the number of threads is small while their interaction simple and well defined (again, by design), with lots of data objects (on the order of many thousands or even millions)

      Thereby, I mark this topic as solved (but your comments are welcome anyway)

      C 1 Reply Last reply 19 Oct 2023, 18:06
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 15 Oct 2023, 18:20 last edited by
        #2

        Hi,

        Looks like the latest KDAB article on QPointer is what you are looking for :-)

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

        D 1 Reply Last reply 15 Oct 2023, 18:30
        1
        • S SGaist
          15 Oct 2023, 18:20

          Hi,

          Looks like the latest KDAB article on QPointer is what you are looking for :-)

          D Offline
          D Offline
          deisik
          wrote on 15 Oct 2023, 18:30 last edited by
          #3

          @SGaist Okay, I will look into it

          D 1 Reply Last reply 15 Oct 2023, 18:56
          0
          • D deisik
            15 Oct 2023, 18:30

            @SGaist Okay, I will look into it

            D Offline
            D Offline
            deisik
            wrote on 15 Oct 2023, 18:56 last edited by deisik
            #4

            As I got it from the article linked, QPointer is not fail-safe as it is not supposed to work across multiple threads:

            Doesn’t this code suffer from the problem that weak_ptr works so hard to prevent? Well yes, it does. However, in practice it does not constitute a problem, because we are never supposed to touch QObjects from arbitrary threads — and this includes deleting them

            QPointer is for checking whether a pointed-to object has not been destroyed before, but it doesn't guarantee that it is not destroyed by another thread right after or even during the check

            C 1 Reply Last reply 15 Oct 2023, 19:51
            0
            • D deisik
              15 Oct 2023, 18:56

              As I got it from the article linked, QPointer is not fail-safe as it is not supposed to work across multiple threads:

              Doesn’t this code suffer from the problem that weak_ptr works so hard to prevent? Well yes, it does. However, in practice it does not constitute a problem, because we are never supposed to touch QObjects from arbitrary threads — and this includes deleting them

              QPointer is for checking whether a pointed-to object has not been destroyed before, but it doesn't guarantee that it is not destroyed by another thread right after or even during the check

              C Offline
              C Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 15 Oct 2023, 19:51 last edited by
              #5

              @deisik Use a shared pointer, like QSharedPointer. That's what they're for - the object lives as long as any of the pointers to it live. The object reference counting in QSharedPointer is atomic, so you can use it across threads.

              D 1 Reply Last reply 15 Oct 2023, 20:01
              2
              • C Chris Kawa
                15 Oct 2023, 19:51

                @deisik Use a shared pointer, like QSharedPointer. That's what they're for - the object lives as long as any of the pointers to it live. The object reference counting in QSharedPointer is atomic, so you can use it across threads.

                D Offline
                D Offline
                deisik
                wrote on 15 Oct 2023, 20:01 last edited by deisik
                #6

                @Chris-Kawa Can it be said that QSharedPointer works as garbage collector for the managed pointer?

                C 1 Reply Last reply 15 Oct 2023, 20:25
                0
                • D deisik
                  15 Oct 2023, 20:01

                  @Chris-Kawa Can it be said that QSharedPointer works as garbage collector for the managed pointer?

                  C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 15 Oct 2023, 20:25 last edited by
                  #7

                  @deisik Not really. Shared pointers are explicit - all holders are responsible for the resource (thus the name "shared") and last person exiting the room turns off the light. Garbage collector would be like a light sensor that turns off the light at some unspecified time after everybody left.

                  1 Reply Last reply
                  5
                  • S Offline
                    S Offline
                    SimonSchroeder
                    wrote on 16 Oct 2023, 08:16 last edited by
                    #8

                    A QObject (and anything derived from it) belongs to a thread. It is either the thread it was created in or moved to using moveToThread() explicitly. If I am not mistaken, you need to delete it inside the thread it belongs to. A shared pointer is the way to go (either QSharedPointer or std::shared_ptr). But you should set the deleter to QObject::deleteLater(). deleteLater() will delete the object inside the correct thread. (I have never used QSharedPointer. Does it do this automatically?)

                    D 1 Reply Last reply 16 Oct 2023, 13:01
                    0
                    • S SimonSchroeder
                      16 Oct 2023, 08:16

                      A QObject (and anything derived from it) belongs to a thread. It is either the thread it was created in or moved to using moveToThread() explicitly. If I am not mistaken, you need to delete it inside the thread it belongs to. A shared pointer is the way to go (either QSharedPointer or std::shared_ptr). But you should set the deleter to QObject::deleteLater(). deleteLater() will delete the object inside the correct thread. (I have never used QSharedPointer. Does it do this automatically?)

                      D Offline
                      D Offline
                      deisik
                      wrote on 16 Oct 2023, 13:01 last edited by deisik
                      #9

                      @SimonSchroeder said in Deleting a shared object:

                      A QObject (and anything derived from it) belongs to a thread. It is either the thread it was created in or moved to using moveToThread() explicitly. If I am not mistaken, you need to delete it inside the thread it belongs to

                      Well, this is the implicit assumption (which I agree with in general, just in case). However, if you delete the object in the last thread using it (while discarding it in all other threads), it doesn't feel like an inherently wrong thing to me

                      But you should set the deleter to QObject::deleteLater(). deleteLater() will delete the object inside the correct thread. (I have never used QSharedPointer. Does it do this automatically?)

                      From what I learned so far, by default it calls the object's default destructor (pardon the pun). But you can specify your own deleter, which (as I see it) can be used for deleting the QSharedPointer object itself (since it is no longer needed then)

                      D 1 Reply Last reply 16 Oct 2023, 17:28
                      0
                      • D deisik
                        16 Oct 2023, 13:01

                        @SimonSchroeder said in Deleting a shared object:

                        A QObject (and anything derived from it) belongs to a thread. It is either the thread it was created in or moved to using moveToThread() explicitly. If I am not mistaken, you need to delete it inside the thread it belongs to

                        Well, this is the implicit assumption (which I agree with in general, just in case). However, if you delete the object in the last thread using it (while discarding it in all other threads), it doesn't feel like an inherently wrong thing to me

                        But you should set the deleter to QObject::deleteLater(). deleteLater() will delete the object inside the correct thread. (I have never used QSharedPointer. Does it do this automatically?)

                        From what I learned so far, by default it calls the object's default destructor (pardon the pun). But you can specify your own deleter, which (as I see it) can be used for deleting the QSharedPointer object itself (since it is no longer needed then)

                        D Offline
                        D Offline
                        deisik
                        wrote on 16 Oct 2023, 17:28 last edited by deisik
                        #10

                        @deisik said in Deleting a shared object:

                        @SimonSchroeder said in Deleting a shared object:
                        From what I learned so far, by default it calls the object's default destructor (pardon the pun). But you can specify your own deleter, which (as I see it) can be used for deleting the QSharedPointer object itself (since it is no longer needed then)

                        So the question that remains is, how can I get a pointer to the QSharedPointer object holding (the pointer to) the data object to be destroyed in the deleter function directly (something like sender() called in a slot)?

                        Or, more generally, should I explicitly delete a QSharedPointer object after it has done its job, or will it take care of itself?

                        S 1 Reply Last reply 16 Oct 2023, 18:23
                        0
                        • D deisik
                          16 Oct 2023, 17:28

                          @deisik said in Deleting a shared object:

                          @SimonSchroeder said in Deleting a shared object:
                          From what I learned so far, by default it calls the object's default destructor (pardon the pun). But you can specify your own deleter, which (as I see it) can be used for deleting the QSharedPointer object itself (since it is no longer needed then)

                          So the question that remains is, how can I get a pointer to the QSharedPointer object holding (the pointer to) the data object to be destroyed in the deleter function directly (something like sender() called in a slot)?

                          Or, more generally, should I explicitly delete a QSharedPointer object after it has done its job, or will it take care of itself?

                          S Offline
                          S Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on 16 Oct 2023, 18:23 last edited by
                          #11

                          @deisik it is shown in the documentation of the corresponding constructor.

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

                          D 1 Reply Last reply 16 Oct 2023, 18:30
                          0
                          • S SGaist
                            16 Oct 2023, 18:23

                            @deisik it is shown in the documentation of the corresponding constructor.

                            D Offline
                            D Offline
                            deisik
                            wrote on 16 Oct 2023, 18:30 last edited by
                            #12

                            @SGaist said in Deleting a shared object:

                            @deisik it is shown in the documentation of the corresponding constructor.

                            It is the data object referenced by the QSharedPointer object which gets destroyed, not the QSharedPointer object itself (unless it is deleted along with the data object)

                            What am I missing?

                            S C 2 Replies Last reply 16 Oct 2023, 18:44
                            0
                            • D deisik
                              16 Oct 2023, 18:30

                              @SGaist said in Deleting a shared object:

                              @deisik it is shown in the documentation of the corresponding constructor.

                              It is the data object referenced by the QSharedPointer object which gets destroyed, not the QSharedPointer object itself (unless it is deleted along with the data object)

                              What am I missing?

                              S Offline
                              S Offline
                              SGaist
                              Lifetime Qt Champion
                              wrote on 16 Oct 2023, 18:44 last edited by
                              #13

                              @deisik you are missing the scope of the QSharedPointer. The custom deleted is call when the QSharedPointer is destroyed provided there are no other QSharedPointer referencing the object.

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

                              D 1 Reply Last reply 16 Oct 2023, 18:51
                              1
                              • S SGaist
                                16 Oct 2023, 18:44

                                @deisik you are missing the scope of the QSharedPointer. The custom deleted is call when the QSharedPointer is destroyed provided there are no other QSharedPointer referencing the object.

                                D Offline
                                D Offline
                                deisik
                                wrote on 16 Oct 2023, 18:51 last edited by
                                #14

                                @SGaist So I should create it on stack if I want it to autodelete, right?

                                S 1 Reply Last reply 16 Oct 2023, 18:53
                                0
                                • D deisik
                                  16 Oct 2023, 18:51

                                  @SGaist So I should create it on stack if I want it to autodelete, right?

                                  S Offline
                                  S Offline
                                  SGaist
                                  Lifetime Qt Champion
                                  wrote on 16 Oct 2023, 18:53 last edited by
                                  #15

                                  @deisik yes. Otherwise it's your job to delete the QSharedPointer object at the correct time.

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

                                  D 1 Reply Last reply 16 Oct 2023, 18:54
                                  0
                                  • D deisik
                                    16 Oct 2023, 18:30

                                    @SGaist said in Deleting a shared object:

                                    @deisik it is shown in the documentation of the corresponding constructor.

                                    It is the data object referenced by the QSharedPointer object which gets destroyed, not the QSharedPointer object itself (unless it is deleted along with the data object)

                                    What am I missing?

                                    C Offline
                                    C Offline
                                    Chris Kawa
                                    Lifetime Qt Champion
                                    wrote on 16 Oct 2023, 18:53 last edited by Chris Kawa
                                    #16

                                    For multithreaded sharing you can use it like this:

                                    vois SomeClass::someMethod()
                                    {
                                       QSharedPointer<MyObject> ptrA {new MyObject, &QObject::deleteLater};
                                       
                                       QtConcurrent::run([](QSharedPointer<MyObject> ptrB){ /* do something with ptrB */ }, ptrA);
                                        
                                       // do something with ptrA
                                    }
                                    

                                    In this case the object will be deleted by either ptrA or ptrB, depending on whether someMethod finishes first or the lambda. Of course you can use any other type of threading. QtConcurrent is just an example here.

                                    QObjects should (in general) be deleted on their thread, so you should be using deleteLater for multithreaded case. This is because object events are processed by the event loop of the thread the object belongs to, so deleting it from another thread is unsafe.

                                    Keep in mind that to share an object QSharedPointers need to be copied. Merely creating a new pointer to the same object will not share it and can lead to crashes, e.g.

                                    MyObject* obj = new MyObject();
                                    QSharedPointer<MyObject> ptr1(obj);  // this creates a reference counted pointer
                                    QSharedPointer<MyObject> ptr2(obj); // this creates another, independent reference counted pointer
                                    

                                    In this case one of these pointers will delete the object when pointer goes out of scope and the app will crash when the other pointer goes out of scope, because it will try to delete it again.
                                    The correct way to share is like this:

                                    MyObject* obj = new MyObject();
                                    QSharedPointer<MyObject> ptr1(obj);  // this creates a reference counted pointer
                                    QSharedPointer<MyObject> ptr2 = ptr1; // this bumps the existing, shared refcount
                                    
                                    1 Reply Last reply
                                    2
                                    • S SGaist
                                      16 Oct 2023, 18:53

                                      @deisik yes. Otherwise it's your job to delete the QSharedPointer object at the correct time.

                                      D Offline
                                      D Offline
                                      deisik
                                      wrote on 16 Oct 2023, 18:54 last edited by
                                      #17

                                      @SGaist said in Deleting a shared object:

                                      @deisik yes. Otherwise it's your job to delete the QSharedPointer object at the correct time.

                                      Gotcha

                                      D 1 Reply Last reply 19 Oct 2023, 12:45
                                      0
                                      • D deisik
                                        16 Oct 2023, 18:54

                                        @SGaist said in Deleting a shared object:

                                        @deisik yes. Otherwise it's your job to delete the QSharedPointer object at the correct time.

                                        Gotcha

                                        D Offline
                                        D Offline
                                        deisik
                                        wrote on 19 Oct 2023, 12:45 last edited by deisik
                                        #18

                                        So I tried to use a QSharedPointer, and it didn't make sense. I have only 3 threads and easily over 1M data objects. In this case specifically, using a QSharedPointer for each of these data objects is a huge overkill incurring as much overhead, both in terms of effort to code and the CPU cycles to run this code – the code to handle the stack of the QSharedPointer pointers themselves (which includes tracking and deleting them)

                                        Instead, I just emit the queued deletion signal from the first thread (where the data object is created) to the second (where the data is actually used, as designed), and the second thread then passes it on after processing to the third (GUI) where the object is deleted in a deterministic, thread-safe manner, with no memory footprint and virtually no extra execution time (compared to keeping track and managing 1M of QSharedPointer instances). Simple, safe and efficient

                                        Indeed, when it becomes a matter of dozens or even hundreds of threads, the QSharedPointer may be a viable and in many cases probably the best solution (I'm far from there yet), but not in the case where the number of threads is small while their interaction simple and well defined (again, by design), with lots of data objects (on the order of many thousands or even millions)

                                        Thereby, I mark this topic as solved (but your comments are welcome anyway)

                                        C 1 Reply Last reply 19 Oct 2023, 18:06
                                        0
                                        • D deisik has marked this topic as solved on 19 Oct 2023, 12:45
                                        • D deisik
                                          19 Oct 2023, 12:45

                                          So I tried to use a QSharedPointer, and it didn't make sense. I have only 3 threads and easily over 1M data objects. In this case specifically, using a QSharedPointer for each of these data objects is a huge overkill incurring as much overhead, both in terms of effort to code and the CPU cycles to run this code – the code to handle the stack of the QSharedPointer pointers themselves (which includes tracking and deleting them)

                                          Instead, I just emit the queued deletion signal from the first thread (where the data object is created) to the second (where the data is actually used, as designed), and the second thread then passes it on after processing to the third (GUI) where the object is deleted in a deterministic, thread-safe manner, with no memory footprint and virtually no extra execution time (compared to keeping track and managing 1M of QSharedPointer instances). Simple, safe and efficient

                                          Indeed, when it becomes a matter of dozens or even hundreds of threads, the QSharedPointer may be a viable and in many cases probably the best solution (I'm far from there yet), but not in the case where the number of threads is small while their interaction simple and well defined (again, by design), with lots of data objects (on the order of many thousands or even millions)

                                          Thereby, I mark this topic as solved (but your comments are welcome anyway)

                                          C Offline
                                          C Offline
                                          Chris Kawa
                                          Lifetime Qt Champion
                                          wrote on 19 Oct 2023, 18:06 last edited by
                                          #19

                                          @deisik I'll be honest. Your conclusions are completely bogus.

                                          using a QSharedPointer for each of these data objects is a huge overkill

                                          How so? It's just a pointer with a refcount.

                                          both in terms of effort to code

                                          Again - what effort - one line to create a pointer (which you do anyway, just with a raw pointer) and one to copy it to the thread.

                                          and the CPU cycles to run the code

                                          What? Copying a QShared pointer is creating a pointer on the stack and atomically bumping a refcount. That's not even noise level of computing.

                                          Instead, I just emit the queued deletion signal

                                          Do you even know how much memory and CPU cycles it takes to emit a cross thread queued signal? At least an order of magnitude more than an atomic refcount, I can assure you.

                                          the object is deleted in a deterministic, thread-safe manner

                                          What if the thread quits before it gets the signal to delete the object? Doesn't sound safe at all. Sounds like memory leak waiting to happen. QSharedPointer is a RAII type. It's deterministic, (really) safe and a lot more performant than passing object around via signals until someone maybe deletes it if they're still around.

                                          Indeed, when it becomes a matter of dozens or even hundreds of threads, the QSharedPointer may be a viable and in many cases probably the best solution, but not in the case where the number of threads is small while their interaction is simple and well defined

                                          That conclusion doesn't make any sense to me. QSharedPointer is basically just a pointer. It's as simple to use as a regular pointer, just that the last one will delete the object. Why do you think it has no use for many objects or few threads is beyond me.

                                          D 1 Reply Last reply 19 Oct 2023, 21:09
                                          6
                                          • C Chris Kawa
                                            19 Oct 2023, 18:06

                                            @deisik I'll be honest. Your conclusions are completely bogus.

                                            using a QSharedPointer for each of these data objects is a huge overkill

                                            How so? It's just a pointer with a refcount.

                                            both in terms of effort to code

                                            Again - what effort - one line to create a pointer (which you do anyway, just with a raw pointer) and one to copy it to the thread.

                                            and the CPU cycles to run the code

                                            What? Copying a QShared pointer is creating a pointer on the stack and atomically bumping a refcount. That's not even noise level of computing.

                                            Instead, I just emit the queued deletion signal

                                            Do you even know how much memory and CPU cycles it takes to emit a cross thread queued signal? At least an order of magnitude more than an atomic refcount, I can assure you.

                                            the object is deleted in a deterministic, thread-safe manner

                                            What if the thread quits before it gets the signal to delete the object? Doesn't sound safe at all. Sounds like memory leak waiting to happen. QSharedPointer is a RAII type. It's deterministic, (really) safe and a lot more performant than passing object around via signals until someone maybe deletes it if they're still around.

                                            Indeed, when it becomes a matter of dozens or even hundreds of threads, the QSharedPointer may be a viable and in many cases probably the best solution, but not in the case where the number of threads is small while their interaction is simple and well defined

                                            That conclusion doesn't make any sense to me. QSharedPointer is basically just a pointer. It's as simple to use as a regular pointer, just that the last one will delete the object. Why do you think it has no use for many objects or few threads is beyond me.

                                            D Offline
                                            D Offline
                                            deisik
                                            wrote on 19 Oct 2023, 21:09 last edited by deisik
                                            #20

                                            @Chris-Kawa said in Deleting a shared object:

                                            What if the thread quits before it gets the signal to delete the object?

                                            If it quits that way, it means there is something wrong with the implementation (read, the code has bugs), not with the design, because by design it will not. And should it, for some inexplicable reason, actually quit, the ensuing memory leak will be the least of my concerns

                                            1 Reply Last reply
                                            0

                                            1/21

                                            15 Oct 2023, 16:49

                                            • Login

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