我已经阅读了 QObject::connect(对于 Qt 5.4)的 documentation,但我有一个关于过载的问题QMetaObject::Connection QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
context
参数究竟是什么?它的目的是什么?它可以用于在线程中的本地事件循环中建立连接吗?
有人可以提供如何/何时使用此重载的示例(当上下文不是 this
时)?
最佳答案
上下文对象用于两种场景。
自动断开
让我们先退一步问问自己: Qt 什么时候断开连接?
使用通常的 connect(sender, signal, receiver, slot)
连接,有三种可能:
disconnect
时; sender
被删除时; receiver
时。 特别是在#2 和#3 的情况下,Qt 以这种方式运行才有意义(实际上,它必须以这种方式运行,否则您会出现资源泄漏和/或崩溃)。
现在: 当使用
connect
重载带一个仿函数时,Qt 什么时候断开连接? 请注意,如果没有
context
参数,则只涉及一个 QObject:发送方。因此答案是:disconnect
时; sender
时。 当然,这里没有接收器对象!所以只有发送方自动控制连接的生命周期。
现在,问题是仿函数可能会捕获一些可能变得无效的额外状态,在这种情况下,连接自动断开是可取的。典型的情况是使用 lambdas:
connect(sender, &Sender::signal,
[&object1, &object2](Param p)
{
use(object1, object2, p);
}
);
如果
object1
或 object2
被删除会发生什么?连接仍将处于事件状态,因此发出信号仍将调用 lambda,后者又将访问已销毁的对象。这有点糟糕......出于这个原因,当涉及到仿函数时,引入了一个
connect
重载,它采用了 上下文对象 。使用该过载建立的连接也将自动断开context
对象被删除时。 例如,当您说很多次您将在仿函数中使用相同的“主”对象时,您可能是对的
connect(button,
&QPushButton::clicked,
otherWidget,
[otherWidget]()
{
otherWidget->doThis(); otherWidget->doThat();
}
);
这只是 Qt 中的一种模式——在为子对象设置连接时,您通常将它们连接到
this
对象上的插槽,因此 this
可能是最常见的上下文。但是,一般来说,您最终也可能会得到类似的结果// manages the lifetime of the resources; they will never outlive this object
struct ResourceManager : QObject
{
Resource res1; // non-QObjects
OtherResource res2;
};
ResourceManager manager;
connect(sender, signal, manager, [&manager](){ use(manager.res1, ...); });
// or, directly capture the resources, not the handle
因此,您正在捕获
manager
的部分状态。在最一般的情况下,当没有
context
对象可用时,如果 lambda 捕获的对象有可能在连接中幸存下来,那么您必须通过弱指针捕获它们,并在尝试访问之前尝试将这些指针锁定在 lambda 内部他们。在特定线程/事件循环中运行仿函数
很快: 指定上下文对象时,仿函数将运行到上下文的线程 中,就像使用接收器对象的普通连接一样。实际上,请注意采用上下文的
connect
重载也采用连接类型(而没有上下文的不采用连接类型——连接总是直接的)。同样,这很有用,因为 QObject 不是可重入的或线程安全的,并且您必须仅在它所在的线程中使用 QObject。如果您的仿函数访问位于另一个线程中的对象,则它必须在该线程中执行;指定该对象作为上下文解决了这个问题。
关于c++ - QObject::connect 函数中的 QObject* 上下文,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27952902/