上下文对象在两种情况下使用。
自动断开连接
让我们先退一步,思考一下:Qt 何时会断开连接?
对于通常的 connect(sender, signal, receiver, slot)
连接,有三种可能:
- 当某人显式调用
disconnect
时;
- 当
sender
被删除时;
- 当
receiver
被删除时。
特别是在情况 #2 和 #3 中,Qt 以这种方式行为是有意义的(实际上,它必须这样行为,否则您将会有资源泄漏和/或崩溃)。
现在问题来了:使用接收器时相应 connect 的重载函数,Qt 何时会断开连接?
请注意,如果没有 context
参数,只涉及一个 QObject:发送者。因此答案是:
- 当某人显式调用
disconnect
时;
- 当
sender
被删除时。
当然,这里没有接收器对象!因此,只有发送者自动控制连接的生存期。
现在,问题是函数对象可能捕获一些额外的状态,这些状态可能无效,因此希望连接自动断开。 典型情况是使用 lambda:
connect(sender, &Sender::signal,
[&object1, &object2](Param p)
{
use(object1, object2, p);
}
);
如果
object1
或者
object2
被删除会发生什么呢?连接仍然存在,因此发射信号仍将调用 lambda 表达式,而 lambda 表达式又将访问已销毁的对象。这有点糟糕...
因此,在涉及到函数对象时引入了一个接受
上下文对象的
connect
重载。使用该重载建立的连接也将自动断开。
- 当
context
对象被删除时。
当你说在 functor 中经常看到相同的“主”对象时,你可能是正确的,例如
connect(button,
&QPushButton::clicked,
otherWidget,
[otherWidget]()
{
otherWidget->doThis(); otherWidget->doThat();
}
);
这只是Qt中的一种模式--在设置子对象的连接时,通常将它们连接到this
对象上的槽函数,因此this
可能是最常见的上下文。然而,总体来说,您也可能得到像下面这样的结果
That's just a pattern in Qt -- when setting up connections for sub-objects, you typically connect them to slots on `this` object, hence `this` is probably the most common context. However, in general, you may also end up with something like
struct ResourceManager : QObject
{
Resource res1;
OtherResource res2;
};
ResourceManager manager;
connect(sender, signal, manager, [&manager](){ use(manager.res1, ...); });
所以,你正在捕获manager
的一部分状态。
在最一般的情况下,当没有context
对象可用时,如果lambda捕获的对象可能会在连接断开后存活,则必须通过弱指针捕获它们,并在lambda中尝试在访问它们之前锁定这些指针。
在特定线程/事件循环中运行函数对象
简而言之:当指定上下文对象时,函数对象将在该上下文线程中运行,就像使用接收器对象的普通连接一样。确实,注意到那个connect
重载函数除了不带上下文参数的连接总是直接连接外,还带有一个连接类型参数。
同样,这很有用,因为QObject不是可重入或线程安全的,并且您必须仅在其所在的线程中使用QObject。如果您的函数对象访问另一个线程中的对象,则必须在该线程中执行;将该对象指定为上下文参数即可解决此问题。