【问题标题】:Disconnecting lambda functions in Qt5在 Qt5 中断开 lambda 函数
【发布时间】: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 并在 = 段错误消失后只留下代码。
  • @kfunk 我确实看到了这个问题,但我无法得出任何结论。您能否进一步解释一下如何以及为什么可以这样做?

标签: c++ lambda qt5


【解决方案1】:

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

std::unique_ptr<QMetaObject::Connection> pconn{new 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> context{new 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();
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      相关资源
      最近更新 更多