我读了documentation的QObject :: connect(对于Qt 5.4),但我有一个关于重载的问题
QMetaObject::Connection QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
context
参数究竟是什么?它的目的是什么?它可以用于在线程中的本地事件循环中构建连接吗?
有人可以举例说明如何/何时使用此重载(当上下文不是this
时)?
答案 0 :(得分:21)
上下文对象用于两种情况。
让我们先退后一步,问自己: 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,而lambda将访问被破坏的对象。这有点不好......
出于这个原因,当涉及到仿函数时,引入了一个connect
重载上下文对象。使用该过载建立的连接也将自动断开
context
对象时当你说很多次你会在那里看到相同的" main"时,你可能是对的。例如,在仿函数中使用的对象
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。如果您的仿函数访问另一个线程中的对象,则必须在该线程中执行;将该对象指定为上下文可以解决问题。