我已经阅读了 QObject::connect(对于 Qt 5.4)的 documentation,但我有一个关于过载的问题
QMetaObject::Connection QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)context 参数究竟是什么?它的目的是什么?它可以用于在线程中的本地事件循环中建立连接吗?

有人可以提供如何/何时使用此重载的示例(当上下文不是 this 时)?

最佳答案

上下文对象用于两种场景。

自动断开

让我们先退一步问问自己: 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);
            }
    );
    

    如果 object1object2 被删除会发生什么?连接仍将处于事件状态,因此发出信号仍将调用 lambda,后者又将访问已销毁的对象。这有点糟糕......

    出于这个原因,当涉及到仿函数时,引入了一个 connect 重载,它采用了 上下文对象 。使用该过载建立的连接也将自动断开
  • context 对象被删除时。

  • 例如,当您说很多次您将在仿函数中使用相同的“主”对象时,您可能是对的
    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。如果您的仿函数访问位于另一个线程中的对象,则它必须在该线程中执行;指定该对象作为上下文解决了这个问题。

    关于c++ - QObject::connect 函数中的 QObject* 上下文,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27952902/

    10-13 08:16