在 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<Connection>
。
请注意,从 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中编写一个函数来断开客户端与服务器的连接? [复制]