[SOLVED] self-deleting objects



  • Let's say I have an object, A, which emits a signal. Object B's slot responds by calling a method of C, which deletes A. The problem (at least in my program) is that A is still on the stack, so this results in a segmentation fault. The way I imagine solving this is to have C run in its own thread and execute with a delay, giving A time to complete. Are there better alternatives? I don't have any experience with threads.

    Thanks!

    [edit: changed the scenario slightly]



  • You could use deleteLater() instead of delete if A and B are derived from QObject.



  • Congratiolations, you have stumbled on the dangers of emitting signals: you give away control over the application to <deighty> knows where in your application, at which point anything can happen, including the deletion or otherwise any manipulation of the emitting object. :-)

    There are tricks to guard against this happening, but they are not all simple. Some basic pointers:

    If possible at all, do the signal emission last in the method that emits them. That prevents some problems.

    Edit: Considder if your signal should not be emitted asynchronously, so after returning to the eventloop even if you trigger it mid-code in your emitting object.

    If you have to have an emit in the middle of your code, try to:

    Make sure that your object is in a consistent state when you do, and

    Assure your application will not break if other methods on the object are called at that point, and

    Check that your object is still alive after the emit took place!

    A trick to check if your object is still alive (last point above), is to have a QPointer<TheClass>(this) variable as a guard in the method where you do the emit. You can then check if this variable was nulled after the emit. If it was, return immediately.

    So:
    @
    void MyClass::someMethod()
    {
    QPointer<MyClass> guard(this);

    //work
    
    //emit something, perhaps progress
    emit someSignal(value);
    
    //check if we're still alive!
    if (!guard)
       return; //exit if we are not
    
    //more work
    return;
    

    }
    @

    There are more advanced tricks that you might employ, but these are some basics.


  • Moderators

    This is pure gold, Andre :) Very nice trick.



  • @Andre: I've changed the scenario in my original post slightly to more accurately reflect my setup: A signals B, B calls method of C, C deletes A, causing a seg fault. The timing of the deletion is important because C then reconstructs A with new parameters. A's signal does appear as its last instruction, but Qt Creator's debugger seems to indicate that A never gets a chance to exit before B's slot fully executes. That's why I was wondering whether I need another thread.

    @KA510: I tried deleteLater(). The problem, as mentioned above, is that the deletion needs to be accompanied by a reconstruction of the object, and I don't see any way to schedule them together.



  • Sorry, but no, I do not see that sequence working like this.

    What you could try, is connect the signal from A to B as a queued signal/slot connection. That way, A will have time to exit the procecure where the signal is emitted in a controlled way. Only when control returns to the eventloop, the signal will be delivered, and you can savely delete A.



  • Does a "queued signal/slot connection" involve QThread? I'm looking around the site, and I'm not sure where to begin on this topic....


  • Moderators

    While queued connections ARE used between QThreads, they can be used independently for connections within a single thread. Adding a Qt::ConnectionType parameter to your connect() call to use a Qt::QueuedConnection just instructs the signal/slot system to push the call to your slot onto a queue, where the event loop will pick it up and execute it on the next event loop iteration. This is in contrast to the slot being called directly. Check the "QObject::connect()":/doc/qt-4.8/qobject.html#connect documentation for more details.



  • Thanks for sharing a very interesting scenario and thanks Andre for a very cool tip :)



  • Adding Qt::QueuedConnection to the connect calls fixed it. Thanks very much, everyone!



  • [quote author="planarian" date="1348164616"]Adding Qt::QueuedConnection to the connect calls fixed it. Thanks very much, everyone![/quote]

    Note that the advice I gave still goes: as your class has no control over how it is connected to other components (directly or via a queued connection), it is a good idea to be careful about what happens when emitting a signal.

    Still, I am happy to hear that using a queued connection solved your problem.



  • Bravo!!! That a cool trick !!! thanks Andre

    I wish we could also dockmark these posts/topics like other pages. Or May be we can add a page to Wiki.



  • [quote author="Sam" date="1348236234"]Bravo!!! That a cool trick !!! thanks Andre

    I wish we could also dockmark these posts/topics like other pages. Or May be we can add a page to Wiki.

    [/quote]
    Thanks :-)

    To give credit where credit is due: I had quite a bit of inspiration from "this":http://delta.affinix.com/dor/ page.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.