我读了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)?
pep*_*ppe 24
上下文对象用于两种方案.
让我们先退后一步,问自己: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);
}
);
Run Code Online (Sandbox Code Playgroud)
会发生什么,如果object1还是object2被删除?连接仍然是活动的,因此发出信号仍将调用lambda,而lambda将访问被破坏的对象.这有点不好......
出于这个原因,当涉及到仿函数时,引入connect了一个带上下文对象的重载.使用该过载建立的连接也将自动断开
context删除对象时当你说很多次你会在那里看到仿函数中使用的"主"对象时,你可能是对的,例如
connect(button,
&QPushButton::clicked,
otherWidget,
[otherWidget]()
{
otherWidget->doThis(); otherWidget->doThat();
}
);
Run Code Online (Sandbox Code Playgroud)
这只是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
Run Code Online (Sandbox Code Playgroud)
所以,你正在捕捉部分状态manager.
在最一般的情况下,当没有context对象可用时,如果lambda捕获的对象有可能在连接中存活,那么必须通过弱指针捕获它们,并尝试在尝试访问它们之前将这些指针锁定在lambda中.
很快:当指定上下文对象时,仿函数将运行到上下文的线程中,就像使用接收器对象的普通连接一样.实际上,请注意,connect采用上下文的重载也采用连接类型(而没有上下文的那个不采用连接类型 - 连接始终是直接的).
同样,这很有用,因为QObject不是可重入的或线程安全的,并且您必须仅在其所在的线程中使用QObject.如果您的仿函数访问另一个线程中的对象,则必须在该线程中执行; 将该对象指定为上下文可以解决问题.