Destroying signal slot connections correctly
-
Hello, I have a question about the destruction of signal-slot connections.
A signal-slot connection is automatically destroyed when either the sender or receiver instance is destroyed. However, when replacing the sender or receiver pointer, the instance itself is usually not destroyed; you simply overwrite the pointer (except in the case of unique_ptr or shared_ptr with a reference count of 0).
For example, the
MyClass::savedsignal remains connected to every Foo instance that was ever set, even if MyClass now contains a completely different Foo pointer.void MyClass::setter(Foo* foo) { m_foo = foo; QObject::connect(m_foo, &Foo::saved, this, &MyClass::saved); }To ensure that
MyClass::savedis only triggered by the currentm_foomember, you need to do the following:void MyClass::setter(Foo* foo) { if (m_foo == foo) return; if (m_foo) // Disconnect all signals from the old m_foo connected to this m_foo.disconnect(this); m_foo = foo; if (m_foo) QObject::connect(m_foo, &Foo::saved, this, &MyClass::saved); }This approach seems cumbersome and prone to errors. My question is: Is my implementation correct, have I misunderstood something, or is there an easier way?
-
connect returns a QMetaObject::Connection
You can pass that as a parameter of QObject::disconnect
So you could write your own class that keeps track of certain connections, and disconnects them on demand. -
Hello, I have a question about the destruction of signal-slot connections.
A signal-slot connection is automatically destroyed when either the sender or receiver instance is destroyed. However, when replacing the sender or receiver pointer, the instance itself is usually not destroyed; you simply overwrite the pointer (except in the case of unique_ptr or shared_ptr with a reference count of 0).
For example, the
MyClass::savedsignal remains connected to every Foo instance that was ever set, even if MyClass now contains a completely different Foo pointer.void MyClass::setter(Foo* foo) { m_foo = foo; QObject::connect(m_foo, &Foo::saved, this, &MyClass::saved); }To ensure that
MyClass::savedis only triggered by the currentm_foomember, you need to do the following:void MyClass::setter(Foo* foo) { if (m_foo == foo) return; if (m_foo) // Disconnect all signals from the old m_foo connected to this m_foo.disconnect(this); m_foo = foo; if (m_foo) QObject::connect(m_foo, &Foo::saved, this, &MyClass::saved); }This approach seems cumbersome and prone to errors. My question is: Is my implementation correct, have I misunderstood something, or is there an easier way?
@Suli-Sahne
As @Asperamanca says. However, that relies on you correctly noting which/all connections. If you no longer what anything connected to oldm_foo, whatever/wherever that might be, then considerm_foo->disconnect()ordisconnect(m_foo, nullptr, nullptr, nullptr). Further details at https://doc.qt.io/qt-6/qobject.html#disconnect. -
@Asperamanca, @JonB
Thank you for your suggestion. I am aware of the various methods to disconnect a connection. My main concern was the complexity of the code, and I was hoping there might be a simpler solution, as I assume others might have faced this issue as well. -
I have created a class that ensures only one connection is active at a time. I would like to post the code, unfortunately akismet.com thinks it would be spam..
In any case, thank you very much for your help.