How to disable lambda function without saving connection

Is there a way to disable Qt connections that are executed for lambda functions without saving connection objects?

I know that this can be done if I save the QMetaObject::Connection returned by the connection function, but I really do not want to do this because there will be a ton of them. I mainly connect to lambda functions so as not to create a bunch of one-time methods and objects, and it seems that if I need to do all this bookkeeping, then SLOTs will be preferable.

+6
source share
4 answers

Here are two approaches to hide accounting problems.

Firstly, we support std::vector , which, when destroyed, disconnects us from the source:

 typedef std::shared_ptr<void> listen_token; struct disconnecter { QMetaObject::Connection conn; disconnecter( QMetaObject::Connection&& c ):conn(std::move(c)) {} ~disconnecter() { QObject::disconnect(conn); } }; template<class F, class T, class M> listen_token QtConnect( T* source, M* method, F&& f ) { return std::make_shared<disconnecter>( QObject::connect( source, method, std::forward<F>(f)); ); } typedef std::vector<listen_token> connections; 

Then we connect as follows:

 connections conns; conns.emplace_back( QtConnect( bob, &Bob::mySignal, [](QString str){ std::cout << "Hello World!\n"; } ) ); 

when a vector is destroyed, connection objects are also destroyed.

This is similar to how other signal / slot systems are processed, where the listener tracks the token and then returns it. But here I save the disconnect object with an opaque type that clears the connection upon destruction.

Note that copying this vector will extend the lifetime of the connection. If the message is sent to a specific instance of the class, save the connections instance in the class and you will not receive the message after the instance is destroyed.


The second approach, based on what @lpapp discovered, is if you have a lambda that you want to call only once in response to a signal, then disable:

 template<class F> struct auto_disconnect_t { F f; std::shared_ptr<QMetaObject::Connection> conn; template<class U> auto_disconnect_t(U&& u): f(std::forward<U>(u)), conn(std::make_shared<QMetaObject::Connection>()) {} template<class... Args> void operator()(Args&&... args)const{ QObject::disconnect(*conn); f( std::forward<Args>(args)... ); } }; template<class T, class M, class F> void one_shot_connect( T* t, M* m, F&& f ) { typedef typename std::decay<F>::type X; auto_disconnect_t<X> helper(std::forward<F>(f)); *helper.conn = QObject::connect( t, m, helper ); }; 

here we are one_shot_connect( bob, Bob::mySignal, [](QString str) { std::cout << "Hello\n" } ); , and the next time the signal is triggered, we get a message, and then the connection is disconnected.

I disconnect before processing the lambda, just in case the lambda causes the signal to light up or something like that.

+4
source

Assuming a connection:

 QObject::connect(senderInstance, &Sender::mySignal, this, []() { // implement slot as a lambda }); 

Then you can easily disable:

 QObject::disconnect(senderInstance, &Sender::mySignal, this, nullptr); 

This will disable all this's slots for Sender::mySignal ; however, it is quite common to have only one such slot, so the end result is that disconnection is simple and without a side effect.

+8
source

You can use a dummy object:

 QObject *obj = new QObject(this); QObject::connect(m_sock, &QLocalSocket::readyRead, obj, [this](){ obj->deleteLater(); 

When the obj object is destroyed, the connection is disconnected because you passed the obj object on the connection.

+4
source

This is the only way to write this:

 QMetaObject::Connection connection = QObject::connect(psender, &MyClass::mySignal, [] () { /* Do the work */ }); QObject::disconnect(connection); 

See the documentation for help on the disconnect method.

bool QObject :: disconnect (const QMetaObject :: Connect and connect) [static]

Disconnect the connection.

If the connection is invalid or is already disconnected, do nothing and return false.

At the end of the day, you will still be making a book with slots, only this lambda seems more localized if you really need to localize it, so I believe that it depends on your personal preferences.

0
source

Source: https://habr.com/ru/post/977196/


All Articles