在 Qt5 中断开 lambda 函数

Posted

技术标签:

【中文标题】在 Qt5 中断开 lambda 函数【英文标题】:Disconnecting lambda functions in Qt5 【发布时间】:2013-02-12 08:49:11 【问题描述】:

是否可以断开 lambda 函数?如果“是”,怎么做?

根据https://qt-project.org/wiki/New_Signal_Slot_Syntax,我需要使用从 QObject::connect 方法返回的QMetaObject::Connection,但是如何将该对象传递给 lambda 函数?

伪代码示例:

QMetaObject::Connection conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this]()
    QObject::disconnect(conn); //<---- Won't work because conn isn't captured

    //do some stuff with sock, like sock->readAll();

【问题讨论】:

你试过了吗? (但也将conn 添加到 lambda 的捕获列表中) @JoachimPileborg 是的,它出于某种原因出现了段错误。一旦我删除 QMetaObject::Connection conn 并在 = 段错误消失后只留下代码。 这里讨论问题:***.com/questions/13847507/… @kfunk 我确实看到了这个问题,但我无法得出任何结论。您能否进一步解释一下如何以及为什么可以这样做? 【参考方案1】:

如果您直接捕获conn,您将通过副本捕获未初始化的对象,这会导致未定义的行为。您需要捕获一个智能指针:

std::unique_ptr<QMetaObject::Connection> pconnnew QMetaObject::Connection;
QMetaObject::Connection &conn = *pconn;
conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this, pconn, &conn]()
    QObject::disconnect(conn);
    // ...

或者使用共享指针,开销稍大:

auto conn = std::make_shared<QMetaObject::Connection>();
*conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this, conn]()
    QObject::disconnect(*conn);
    // ...

从 Qt 5.2 开始,您可以改为使用上下文对象:

std::unique_ptr<QObject> contextnew QObject;
QObject* pcontext = context.get();
QObject::connect(m_sock, &QLocalSocket::readyRead, pcontext,
    [this, context = std::move(context)]() mutable 
    context.release();
        // ...
 );

【讨论】:

您能否更详细地解释第一个示例?为什么要创建指针,然后引用指针并将两者都传递给 lambda?编辑:是不是可以做类似的事情: *pconn = QObject::connect(...);最终将 conn 完全排除在外? 在第一个例子中,conn 的生命周期由代码块决定,而 lambda 函数仍然使用它。如果conn 还活着,那就太幸运了。在这种情况下,您肯定需要shared_ptr&lt;Connection&gt; 请注意,从 Qt 5.2 开始,还有一个采用上下文对象的重载。当发送者或上下文对象被销毁时,连接将被断开。 @iammilind clear 不是std::unique_ptr 的成员。 release 删除指针。 context 只是一个同步对象。通过将插槽连接到 this 实例并在处理程序中将其删除,Qt 也会自动释放信号插槽连接。如果接收者被删除,Qt 会为所有连接执行此操作。 这段代码似乎没有经过测试......并且可能无法正常工作。【参考方案2】:

ecatmur 答案中的上下文解决方案是最简单的选择,但我认为智能指针的使用使其更难理解。我会改用原始指针:

QObject *context = new QObject(this);
connect(sender, &Sender::signal, context, [context] 
  delete context;
  // ...
);

【讨论】:

【参考方案3】:

您可以将conn 定义为.h 文件中的私有变量。 QMetaObject::Connection conn。 在 lambda 函数中,您可以使用conn 并断开它。

 conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [=]()
    QObject::disconnect(conn); //<---- Won't work because conn isn't captured

    //do some stuff with sock, like sock->readAll();

【讨论】:

以上是关于在 Qt5 中断开 lambda 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 Sumologic 的 AWS lambda 面临的套接字断开连接问题?

如何在C中编写一个函数来断开客户端与服务器的连接? [复制]

断开 Mutation Observer 与回调函数的连接

如何在html5中断开连接后重新连接到套接字

socket.io 客户端在长 Node.js 函数中自动断开连接

判断socket断开连接的方法