Dav*_*ing 20
假设连接:
QObject::connect(senderInstance, &Sender::mySignal, this, []() {
// implement slot as a lambda
});
Run Code Online (Sandbox Code Playgroud)
然后您可以轻松断开连接:
QObject::disconnect(senderInstance, &Sender::mySignal, this, nullptr);
Run Code Online (Sandbox Code Playgroud)
这将断开所有this's插槽Sender::mySignal; 但是,只有一个这样的插槽是很常见的,因此最终的结果是简单地执行断开并且没有副作用.
您可以使用虚拟对象:
QObject *obj = new QObject(this);
QObject::connect(m_sock, &QLocalSocket::readyRead, obj, [this](){
obj->deleteLater();
Run Code Online (Sandbox Code Playgroud)
当obj被销毁时,连接断开,因为你在连接上传递了obj.
这是隐藏簿记问题的两种方法。
首先,我们维护一个std::vector销毁该销毁资源的源:
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;
Run Code Online (Sandbox Code Playgroud)
然后我们如下连接:
connections conns;
conns.emplace_back( QtConnect( bob, &Bob::mySignal, [](QString str){ std::cout << "Hello World!\n"; } ) );
Run Code Online (Sandbox Code Playgroud)
当向量被破坏时,连接对象也被破坏。
这类似于处理其他信号/插槽系统的方式,侦听器跟踪令牌,然后将其返回。但是在这里,我将断开连接对象保留为不透明类型,以清除破坏时的连接。
请注意,复制该向量将延长连接的寿命。如果消息将发送到类的特定实例,connections则将一个实例存储在该类中,实例销毁后您将不会收到消息。
基于@lpapp找到的第二种方法是,如果您有一个lambda想要只响应一次信号而调用一次,然后断开连接:
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 );
};
Run Code Online (Sandbox Code Playgroud)
我们在这里one_shot_connect( bob, &Bob::mySignal, [](QString str) { std::cout << "Hello\n" } );,下次信号触发时,我们会收到消息,然后断开连接。
我会在处理您的Lambda之前断开连接,以防万一Lambda导致信号触发或其他原因。