gpt4 book ai didi

c++ - Qt 插槽和 C++11 lambda

转载 作者:IT老高 更新时间:2023-10-28 13:58:13 27 4
gpt4 key购买 nike

我有一个 QAction 项目,我初始化如下:

QAction* action = foo->addAction(tr("Some Action"));
connect(action, SIGNAL(triggered()), this, SLOT(onSomeAction()));

然后 onSomeAction 看起来像:

void MyClass::onSomeAction()
{
QAction* caller = qobject_cast<QAction*>(sender());
Q_ASSERT(caller != nullptr);

// do some stuff with caller
}

这很好,我得到了 caller 对象,我可以按预期使用它。然后我尝试使用 C++11 的方式来连接对象,如下所示:

connect(action, &QAction::triggered, [this]()
{
QAction* caller = qobject_cast<QAction*>(sender());
Q_ASSERT(caller != nullptr);

// do some stuff with caller
});

caller 始终为空,因此 Q_ASSERT 触发。如何使用 lambdas 获取发件人?

最佳答案

简单的答案是:你不能。或者,您不想(或不需要!)使用 sender()。只需捕获并使用 action

//                                Important!
// vvvv
connect(action, &QAction::triggered, this, [action, this]() {
// use action as you wish
...
});

this 作为仿函数的对象上下文的规范确保了如果 Action 或 this(一个 QObject) 不复存在。否则,仿函数会尝试引用悬空指针。

一般来说,当捕获传递给 connect 的仿函数的上下文变量时,必须满足以下条件,以避免使用悬空指针/引用:

  1. connect的源对象和目标对象的指针可以按值来捕获,如上。保证如果调用仿函数,连接的两端都存在。

    connect(a, &A::foo, b, [a, b]{});

    ab 位于不同线程的场景需要特别注意。不能保证一旦进入functor,某个线程不会删除任何一个对象。

    一个对象只在其 thread() 中或在 thread() == nullptr 的任何线程中被破坏是惯用的。由于线程的事件循环调用仿函数,所以对于 b 来说,空线程永远不会成为问题——没有线程,仿函数将不会被调用。唉,对于 b 的线程中的 a 的生命周期没有任何保证。因此,通过值来捕获 Action 的必要状态会更安全,这样 a 的生命周期就不是问题了。

    // SAFE
    auto aName = a->objectName();
    connect(a, &A::foo, b, [aName, b]{ qDebug() << aName; });
    // UNSAFE
    connect(a, &A::foo, b, [a,b]{ qDebug() << a->objectName(); });
  2. 如果您绝对确定它们指向的对象的生命周期与连接的生命周期重叠,则可以按值捕获指向其他对象的原始指针。

    static C c;
    auto p = &c;
    connect(..., [p]{});
  3. 对对象的引用同上:

    static D d;
    connect(..., [&d]{});
  4. 不从 QObject 派生的不可复制对象应通过其共享指针按值捕获。

    std::shared_ptr<E> e { new E };
    QSharedPointer<F> f { new F; }
    connect(..., [e,f]{});
  5. QObject可以被一个QPointer捕获;在仿函数中使用之前必须检查其值。

    QPointer<QObject> g { this->parent(); }
    connect(..., [g]{ if (g) ... });
  6. QObject 生活在其他线程中,必须被共享指针或弱指针捕获。他们的 parent 必须在销毁之前取消设置,否则您将有双重删除:

    class I : public QObject {
    ...
    ~I() { setParent(nullptr); }
    };

    std::shared_ptr<I> i { new I };
    connect(..., [i]{ ... });

    std::weak_ptr<I> j { i };
    connect(..., [j]{
    auto jp = j.lock();
    if (jp) { ... }
    });

关于c++ - Qt 插槽和 C++11 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19719397/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com