Results 1 to 12 of 12

Thread: Questions about signals/slots and QObject lifetimes

  1. #1
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Questions about signals/slots and QObject lifetimes

    I'm trying to find documentation about the deep nature of Signals and Slots (which are well documented in the source)...

    for instance, connect() is frequently called from 'this', but if 'this' calls:

    Qt Code:
    1. connect(that, SIGNAL(_something()), other, SLOT(_else()));
    To copy to clipboard, switch view to plain text mode 

    then is the connection connected to the lifetime of 'this', or is it attached to an internal database so that deleting 'this' will allow the connection to persist?

    I'm hoping that deleting 'this' will destroy the connection, but 'this' is separate from 'that' and 'other', so the question is, are connections connected to the creator or the objects?
    Last edited by themolecule; 23rd May 2014 at 15:16.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    If you look at the signature of the connect method you used here, you will see that it is a static method of QObject.

    So the "this" object is not involved at all with this connection.

    The connection will persist as long as its sender and receiver exist or it is undone using QObject::disconnect().

    Cheers,
    _

  3. #3
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,325
    Thanks
    316
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    If you look at the signature of the connect method you used here, you will see that it is a static method of QObject.
    Well, yes, but the OP's question really boils down to: if one of the instances involved in the connection (either the sender or the receiver) is destroyed, is the connection also destroyed?

    The answer to that is "yes". If that was not the case, things would likely be crashing all over the place due to slots being invoked with dangling, deleted pointers.

    QObject has a QObject::destroyed() signal which you can use to detect when an object you are interested in has been (or is about to be) destroyed. For example, if you keep a pointer to some QObject instance in a data structure, and that QObject's lifetime was controlled by something else, you'd want to make sure that pointer was still valid before using it. If you connect to the instance's destroyed() signal, you can be notified when it goes out of scope and can take appropriate action (like set your stored pointer variable to NULL).

  4. #4
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Questions about signals/slots and QObject lifetimes

    You are both correct, thank you.

    I failed to remember that connect() is a static member of QObject, which is, basically, this-less when called, so of course it makes sense that 'this' can be deleted without regard for 'that' or 'other' as far as connections go.

    And both 'that' and 'other' remain consistent upon disconnect() or delete (probably because of slots), so if I want the lifetime of connect() to be connected to 'this', I need listeners on both sides.

    Thanks!


    Added after 14 minutes:


    For anyone else interested:

    Qt Code:
    1. connect(that, SIGNAL(_something()), other, SLOT(_else()));
    2. connect(that, SIGNAL( destroyed(), this, SLOT(disconnection()) );
    3. connect(other, SIGNAL( destroyed(), this, SLOT(disconnection()) );
    4.  
    5. //...
    6.  
    7. void someClass::disconnection()
    8. {
    9. //someBaseClass *o = dynamic_cast<someBaseClass *>(sender()); //not needed
    10. //disconnect(that, SIGNAL(/*xyz*/), other, SLOT(/*tuv*/)); //not needed
    11.  
    12. this->deleteLater(); //the whole point
    13. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by themolecule; 23rd May 2014 at 17:52.

  5. #5
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,540
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    RTFM (read this fine manual). From QObject destructor doc : All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue.

  6. #6
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Questions about signals/slots and QObject lifetimes

    Wow man... the Fine Manual does not describe connections between objects when created from another object, which is a distinctly different question.

    I think you may consider Reading The Fine Manual A Little More Closely in relation to the question, and as well read the responses.

    It's a basic thing... offer something constructive that adds solution to the problem, or at least offer context to how the solution you offer makes sense, to separate your copy/paste from plain RTFM... please!

  7. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    Quote Originally Posted by themolecule View Post
    Qt Code:
    1. connect(that, SIGNAL(_something()), other, SLOT(_else()));
    2. connect(that, SIGNAL( destroyed(), this, SLOT(disconnection()) );
    3. connect(other, SIGNAL( destroyed(), this, SLOT(disconnection()) );
    4.  
    5. //...
    6.  
    7. void someClass::disconnection()
    8. {
    9. //someBaseClass *o = dynamic_cast<someBaseClass *>(sender()); //not needed
    10. //disconnect(that, SIGNAL(/*xyz*/), other, SLOT(/*tuv*/)); //not needed
    11.  
    12. this->deleteLater(); //the whole point
    13. }
    To copy to clipboard, switch view to plain text mode 
    If your slot does really only call deleteLater() you might find it interesting that deleteLater() is already a slot itself

    Cheers,
    _

  8. #8
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Questions about signals/slots and QObject lifetimes

    Thanks! You mention an excellent point:

    Qt Code:
    1. connect(that, SIGNAL(_something()), other, SLOT(_else()));
    2. connect(that, SIGNAL( destroyed(), this, SLOT(deleteLater()) );
    3. connect(other, SIGNAL( destroyed(), this, SLOT(deleteLater()) );
    To copy to clipboard, switch view to plain text mode 

    is more elegant.

  9. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,325
    Thanks
    316
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    Another thing the fine manual tells us is that not only is connect a static QObject method, it is also present as a member function. So, calling the static version:

    Qt Code:
    1. connect(that, SIGNAL( destroyed(), this, SLOT(deleteLater()) );
    To copy to clipboard, switch view to plain text mode 

    is the same as calling the member version with this syntax:

    Qt Code:
    1. connect(that, SIGNAL( destroyed(), SLOT(deleteLater()) );
    To copy to clipboard, switch view to plain text mode 

    I'm not really sure what you're trying to accomplish with all the this, that, and theOther code and deleteLater(). If you give your QObject instances non-NULL parents, then their lifetimes are controlled by those parents. As the usually fine but sometimes not complete enough manual says, all connections and events associated with those objects get cleaned up when the objects are destroyed, so except in rare circumstances it usually is unnecessary to call deleteLater() on something. If "this" is owned by "that", then when "that" is destroyed, so will be "this". If you really want the lifetime of "this" to be controlled by "that" (in essence, that's exactly what your signal / slot connection is doing), then make "this" a child of "that" and it will be taken care of for you.

    The only times I have had to use deleteLater() is when I store a pointer to some instance in a data structure and I replace that pointer with a different instance in a slot. I'll call it then with the old pointer so things get cleaned up in a timely way. Otherwise, the memory used by the old pointer would hang around until the parent data structure goes away, along with the new one. You can't simply delete() the old pointer while in a slot without causing a crash. deleteLater() ensures the instance remains in scope until it is no longer needed.
    Last edited by d_stranz; 24th May 2014 at 17:22.

  10. #10
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Questions about signals/slots and QObject lifetimes

    Thanks, that is also helpful.

    What I'm trying to accomplish is essentially founded in Graph Theory.

    In Qt, a connection 'just is'. It's made, and its lifetime is connected to the endpoints, but that's it.

    However, if you consider the idea that a connection itself can be an object, like the relationship between a sender and receiver has a type and intention, and a sender and receiver can be connected many times with different roles, it becomes interesting. Within Qt, it may be that a signal and slot are being connected repeatedly, but the desire is that each of those connections are meaningful and unique. One could create lots of different signals and lots of slots to do this, but another way is to embed the intention as part of the signal itself, which would be a case for having a basic thing like:

    Qt Code:
    1. class sender : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. sender();
    7.  
    8. signals:
    9. trigger(roleType role, QVariantMap data);
    10. };
    11.  
    12. class receiver : public QObject
    13. {
    14. Q_OBJECT
    15.  
    16. public:
    17. recevier();
    18.  
    19. slots:
    20. triggered(roleType role, QVariantMap data);
    21. };
    22.  
    23. ...
    24.  
    25. //somewhere else
    26. connect(_sender, SIGNAL(trigger(roleType,QVariantMap)), _receiver, SLOT(triggered(roleType,QVariantMap)));
    To copy to clipboard, switch view to plain text mode 

    But the sender may not know what its role is when emit()ing, and the connection wants to be smarter than that, so there wants to be an object layer and a connection layer that both offer intelligence to the system.

    My thinking was that if connections are attached to the creator, then the lifetime of the connection object would take care of any cleanup. But instead it seems that the connection object wants to broker messages between endpoints and inject intelligence (filtering, queueing, routing, etc) that way. Which conceptually is simple enough but in Qt it ends up being a connect() from the sender to the connection, and then the connection to the receiver. It becomes a proxy link.

    So now that I know that a connection object must maintain and proxy the connections (ie, Qt Signals/Slots aren't quite right all alone between objects for this purpose), I have to make connection objects that share qt signal/slot signatures (for API convenience), but internally the intelligence is in the connection object's polymorphism.

    It becomes difficult when you have varieties of nodes that are descendants of a common base class who want to be agnostic to signals/slots, and the total set of connection roles are not known, but want to be able to be connected arbitrarily.

    I'm trying to make something like Qt's signals/slots but with an extra bit in there that is not merely a connection, but a filtering/queueing/routing mechanism between threads and networked machines. It's a different layer of linkage, so parent/child associations are helpful during destructors, but a connection's lifetime may not be directly connected to the endpoints' lifetime.

    So maybe this is better:

    Qt Code:
    1. class base : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. base(QObject *parent=0) : QObject(parent) {}
    7. virtual ~base() {}
    8. };
    9.  
    10. class sender : public base
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. sender(QObject *parent=0) : base(parent) {}
    16. virtual ~sender() {}
    17.  
    18. signals:
    19. trigger(QVariantMap data);
    20. };
    21.  
    22. class receiver : public base
    23. {
    24. Q_OBJECT
    25.  
    26. public:
    27. recevier(QObject *parent=0) : base(parent) {}
    28. virtual ~receiver() {}
    29.  
    30. slots:
    31. triggered(QVariantMap data);
    32. };
    33.  
    34. class connection : public QObject
    35. {
    36. Q_OBJECT
    37.  
    38. public:
    39. connection(base *sender, base *receiver) : QObject(sender)
    40. {
    41. connect(sender, SIGNAL(trigger(QVariantMap)), this, SLOT(incoming(QVariantMap)));
    42. connect(this, SIGNAL(outgoing(QVariantMap)), receiver, SLOT(triggered(QVariantMap)));
    43.  
    44. connect(sender, SIGNAL(destroyed()), this, SLOT(deleteLater()));
    45. connect(receiver, SIGNAL(destroyed()), this, SLOT(deleteLater()));
    46. }
    47. virtual ~connection()
    48. {
    49. //connections will be destroyed automatically here
    50. }
    51.  
    52. signals:
    53. void outgoing(QVariantMap data);
    54.  
    55. slots:
    56. virtual void incoming(QVariantMap data)
    57. {
    58. //something interesting here which may or may not emit a signal, or be overridden by a subclass
    59.  
    60. if (interesting)
    61. emit outgoing(data);
    62. }
    63. };
    64.  
    65. //other code...
    66.  
    67. //somewhere else
    68. sender *_sender = new sender(this);
    69. receiver *_receiver = new receiver(this);
    70. connection *c = new connection(_sender, _receiver);
    To copy to clipboard, switch view to plain text mode 

    Sorry to ramble, but upon asking the question the structure becomes more clear, and those that have answered point out simple reductions that Qt's awesome engineering provide. It's surprisingly easy to overlook simple conveniences when swimming through complication!

    thanks again!
    Last edited by themolecule; 24th May 2014 at 19:56.

  11. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,325
    Thanks
    316
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Questions about signals/slots and QObject lifetimes

    I don't know where Qt actually stores connection instances, probably somewhere deep inside the meta-object system. So, because there *is* an instance of QMetaObject::Connection created when you call the connect() methods, there is a graph theoretical object associated. And you can attach properties to the connection (see QMetaObject::userProperty()). Undoubtedly somewhere in the connect() code, there are further connections made between destroyed() and deleteLater() on the two object instances being connected, otherwise the connection would have no way to ensure that the two instances were still valid.

    but a connection's lifetime may not be directly connected to the endpoints' lifetime
    Think about what you're saying here - that you can have an instance of a connection object that doesn't actually connect anything. If that's the case, then what purpose does it serve? Unless it is expensive to create the instance itself (not make the actually link between the two endpoints), then it might make sense to have a connection instance with a lifetime different from either endpoint. But usually the cost is in making the link, so in that case, why not have the connection exist only as long as both of its endpoints?

  12. #12
    Join Date
    Jul 2007
    Location
    New York
    Posts
    45
    Thanks
    5
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Questions about signals/slots and QObject lifetimes

    I agree, and I just added a piece of code to clarify, that yes a Qt connection's lifetime is absolutely connected to its endpoints, and what my sample code shows is that what I'm calling a connection object can act the same way if properly cabled together.

    I'm just making sure that I'm not missing something in the nuances of what Qt already has to offer.


    Added after 26 minutes:


    This is interesting...

    QMetaObject::userProperty()

    thanks!
    Last edited by themolecule; 24th May 2014 at 19:11.

Similar Threads

  1. Replies: 2
    Last Post: 18th April 2013, 12:15
  2. Replies: 1
    Last Post: 7th February 2011, 15:44
  3. Signals and Slots - Moc QObject Problem
    By GBayo1 in forum Qt Programming
    Replies: 6
    Last Post: 22nd March 2010, 16:35
  4. Signals and Slots questions
    By Janek in forum Qt Programming
    Replies: 3
    Last Post: 29th December 2009, 21:47
  5. qobject connect questions
    By VireX in forum Newbie
    Replies: 5
    Last Post: 20th May 2007, 09:04

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.