QObject :: connect函数中的QObject*上下文

Nic*_*aus 11 c++ qt c++11

我读了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)连接有三种可能性:

  1. 当某人明确地打电话时disconnect;
  2. 何时sender被删除;
  3. 何时receiver被删除.

特别是在#2和#3的情况下,Qt的行为恰好是有意义的(实际上,它必须以这种方式运行,否则你会遇到资源泄漏和/或崩溃).


现在:当使用connect带有仿函数的重载时,Qt何时断开连接?

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

  1. 当某人明确地打电话时disconnect;
  2. 何时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了一个带上下文对象的重载.使用该过载建立的连接也将自动断开

  1. 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.如果您的仿函数访问另一个线程中的对象,则必须在该线程中执行; 将该对象指定为上下文可以解决问题.

  • 我相信上下文对象有另一个作用:用于指定运行仿函数的线程 (2认同)
  • 这应该在Qt文档中! (2认同)