prohibiting duplicate connections?



  • I had been wondering for some time about how the slot connections were implemented so I reviewed the QObject connect and disconnect code the other day. I was particularly interested in any safeguards to keep from making redundant connections. I noted that UniqueConnection is an option, but not for functors, lambdas, or signals/slots in different threads. I'm wondering why...

    Seems like a unique hash map of each attemption connect() would be a no-brainer, and could allow prohibiting multiple redundant connections for all of the cases where they are not currently supported.

    Anyone claim to know the mind of the developers, and why UniqueConnection is not supported for all connect() calls?

    Just curious


  • Lifetime Qt Champion

    Hi,

    There are overloads for that, see for example this one here.

    As for the threads involvement, they have nothing to do with unique connections.

    [Edit: SGaist] Incomplete answer as I mainly focused on the thread aspect.



  • The inline code documentation for 5.12.1 states that UniqueConnection is not supported in the cases I outlined above. That's my quandry...why?...What am I missing, that kept the devs from fully utilizing the UniqueConnection parameter?

    qtbase/src/corelib/kernel/qobject.cpp: line 2653

    // \note Qt::UniqueConnections do not work for lambdas, non-member functions
        and functors; they only apply to connecting to member functions.
    


  • @SGaist said in prohibiting duplicate connections?:

    Hi,

    There are overloads for that, see for example this one here.

    As for the threads involvement, they have nothing to do with unique connections.

    The link given by @SGaist here has this note as well
    Note: Qt::UniqueConnections do not work for lambdas, non-member functions and functors; they only apply to connecting to member functions.


  • Lifetime Qt Champion

    @Kent-Dorfman
    Hi
    lambas are pr nature anonymous and UniqueConnections uses the metasystem from QObject
    so i would guess on they thought it too involving to support 2 systems.


  • Qt Champions 2017

    @Kent-Dorfman said in prohibiting duplicate connections?:

    That's my quandry...why?...What am I missing, that kept the devs from fully utilizing the UniqueConnection parameter?

    The quick answer is that you can't distinguish a lambda from the same lambda. Think of a lambda (and a functor) as an object, so while two instances of the same (anonymous) class may do the same, they are still distinct objects.



  • Does it help to see if it is connected at all:

    bool 	isSignalConnected(const QMetaMethod &signal) const
    int 	receivers(const char *signal) const
    

    https://doc.qt.io/qt-5.12/qobject.html#protected-functions
    This won't help if you need more than one connection of different slots/signals though. Too bad there isn't a way to check if a particular connection has been made. You may need to monitor this yourself with a wrapper. Probably won't help with lambdas though.



  • Well, it looks like there are no easy answers to this. Certainly, a wrapper at the application level is less desirable than seeing it better implemented in the framework...aside from lambdas and functors, seems that any other "defined" function should fit easily into the lookup table scheme, but the devs didn't go that route.

    Probably no sense in further discussion.


  • Qt Champions 2018

    @Kent-Dorfman

    I think you should ask this question on the Development mailing list. The developers can tell you better, why this limitations exist and if there is a chance to change it. (If you do, please post a link to the archive afterwards, you can reach it from the link above - thanks).

    Probably no sense in further discussion.

    At least not here, because we don't know the deep details.

    Regards


  • Qt Champions 2017

    At least not here, because we don't know the deep details.

    It's a twofold problem:

    1. The connect needs a context QObject, if not specified that's the sender.
      Then the question becomes is the following the same connection:
    QObject * otherObject;
    void freeFunction();
    
    QObject::connect(this, &MyClass::someSignal, otherObject, freeFunction);
    QObject::connect(this, &MyClass::someSignal, this, freeFunction);
    

    where, conceivably, otherObject may be in a different thread. Nobody knows how these two should be distinguished exactly - in some cases they may be considered the same, in some they may not. freeFunction isn't attached to the class of this, nor to the class of otherObject.

    1. A functor (a.k.a. lamda, a.k.a. function object, std::function, etc.) more often than not has (internal) state. So two instances of the same type (i.e. two lambdas) can't be distinguished due to the fact that the state is not known to Qt. Example:
    auto functor1 = [this] () -> void {
        qDebug() << "Functor";
    }
    auto functor2 = functor1; //< Object copy here! We are dealing with another entity entirely!
    
    QObject::connect(this, &MyClass::someSignal, this, functor1);
    QObject::connect(this, &MyClass::someSignal, this, functor2); //< functor2 isn't functor1
    

    And to add insult to injury:

    QObject::connect(this, &MyClass::someSignal, this, functor1); //< Object copy of functor1!
    QObject::connect(this, &MyClass::someSignal, this, functor1); //< Object copy of functor1, again!
    

Log in to reply