QObject::connect函数中的QObject* context参数

18
我已阅读了关于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)的如何/何时使用示例?
1个回答

50

上下文对象在两种情况下使用。

自动断开连接

让我们先退一步,思考一下:Qt 何时会断开连接?

对于通常的 connect(sender, signal, receiver, slot) 连接,有三种可能:

  1. 当某人显式调用 disconnect 时;
  2. sender 被删除时;
  3. receiver 被删除时。

特别是在情况 #2 和 #3 中,Qt 以这种方式行为是有意义的(实际上,它必须这样行为,否则您将会有资源泄漏和/或崩溃)。


现在问题来了:使用接收器时相应 connect 的重载函数,Qt 何时会断开连接?

请注意,如果没有 context 参数,只涉及一个 QObject:发送者。因此答案是:

  1. 当某人显式调用 disconnect 时;
  2. sender 被删除时。

当然,这里没有接收器对象!因此,只有发送者自动控制连接的生存期。

现在,问题是函数对象可能捕获一些额外的状态,这些状态可能无效,因此希望连接自动断开。 典型情况是使用 lambda:

connect(sender, &Sender::signal, 
        [&object1, &object2](Param p) 
        { 
            use(object1, object2, p);
        }
);
如果 object1 或者 object2 被删除会发生什么呢?连接仍然存在,因此发射信号仍将调用 lambda 表达式,而 lambda 表达式又将访问已销毁的对象。这有点糟糕...


因此,在涉及到函数对象时引入了一个接受上下文对象connect重载。使用该重载建立的连接也将自动断开。
  1. 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
// 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。如果您的函数对象访问另一个线程中的对象,则必须在该线程中执行;将该对象指定为上下文参数即可解决此问题。


3
我认为上下文对象还有另一个作用:指定运行函数对象的线程。 - JKSH
4
这应该写进Qt文档里面! - Julien-L
非常清晰的答案! - isudfv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接