【问题标题】:QObject* context in QObject::connect functionQObject::connect 函数中的 QObject* 上下文
【发布时间】:2015-03-13 05:23:28
【问题描述】:

我已经阅读了 QObject::connect 的 documentation(对于 Qt 5.4),但我对过载有疑问

QMetaObject::Connection QObject::connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)

context 参数到底是什么?它的目的是什么?可以用来在线程的本地事件循环中建立连接吗?

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

【问题讨论】:

    标签: c++ qt c++11


    【解决方案1】:

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

    自动断开

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

    如果object1object2 被删除会怎样?连接仍然是活动的,因此发出信号仍然会调用 lambda,而后者又会访问被破坏的对象。这有点糟糕......


    因此,当涉及到仿函数时,引入了一个采用 上下文对象connect 重载。使用该重载建立的连接也将自动断开

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

    【讨论】:

    • 我相信上下文对象还有另一个作用:用于指定运行仿函数的线程
    • 这应该在Qt文档中!
    猜你喜欢
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 2015-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多