Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disconnect a lambda function without storing connection [duplicate]

Tags:

c++

c++11

lambda

qt

Is there a way to disconnect Qt connections that are made to lambda functions without storing connection objects?

I know it's possible to do if I store the QMetaObject::Connection returned from the connect function, but I don't really want to do that because there would be a ton of them. I mainly connect to lambda functions to avoid creating a bunch of one-off methods and objects, and it seems like if I need to do all that bookkeeping that SLOTs would be more preferable.

like image 357
Nicolas Holthaus Avatar asked Oct 24 '14 17:10

Nicolas Holthaus


People also ask

How do you stop lambda invocation?

If you want to stop future invocations a simple way to do this is by removing the related permission from the IAM role associated with your Lambda. You can find a link to the IAM role in the permissions tab of the Lambda.

How do you duplicate a lambda function?

There is no provided function to copy/clone Lambda Functions and API Gateway configurations. You will need to create new a new function from scratch. If you envision having to duplicate functions in the future, it may be worthwhile to use AWS CloudFormation to create your Lambda Functions.


3 Answers

Assuming a connection:

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

Then you can easily disconnect by:

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

This would disconnect all of this'sslots for Sender::mySignal; however, it is quite common to have only one such slot, so the end result is the disconnection is performed simply and with no side effect.

like image 123
David Ching Avatar answered Oct 04 '22 03:10

David Ching


You can use a dummy object:

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

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

like image 24
mabg Avatar answered Oct 04 '22 03:10

mabg


Here are two approaches to hide the bookkeeping issues.

First, we maintain a std::vector which, on destruction, 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 the vector is destroyed, the connection objects are also destroyed.

This is similar to how other signal/slot systems are handled, where the listener keeps track of a token, then returns it. But here, I keep the disconnection object in an opaque type that cleans up the connection on destruction.

Note that copying that vector will extend the lifetime of the connection. If the message is going to a particular instance of a class, store a connections instance in the class, and you won't get messages after the instance is destroyed.


A second approach, based off what @lpapp found, is if you have a lambda that you want to call only once in response to a signal, then disconnect:

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 one_shot_connect( bob, &Bob::mySignal, [](QString str) { std::cout << "Hello\n" } );, and the next time the signal fires we get the message, and then the connection is disconnected.

I disconnect before processing your lambda, just in case the lambda causes the signal to fire or something.

like image 24
Yakk - Adam Nevraumont Avatar answered Oct 04 '22 03:10

Yakk - Adam Nevraumont