Ответ 1
Простой ответ: вы не можете. Или, скорее, вы не хотите (или нуждаетесь!) Использовать sender()
. Просто запишите и используйте action
.
// Important!
// vvvv
connect(action, &QAction::triggered, this, [action, this]() {
// use action as you wish
...
});
Спецификация this
как контекста объекта для функтора гарантирует, что функтор не будет вызван, если действие или this
(a QObject
) перестают существовать. В противном случае функтор попытается ссылаться на оборванные указатели.
В общем случае при захвате переменных контекста для функтора, переданного в connect
, должно выполняться следующее: во избежание использования оборванных указателей/ссылок:
-
Указатели исходного и целевого объектов
connect
могут быть записаны по значению, как указано выше. Гарантируется, что при вызове функтора оба конца соединения существуют.connect(a, &A::foo, b, [a, b]{});
Сценарии, в которых
a
иb
находятся в разных потоках, требуют особого внимания. Невозможно гарантировать, что после ввода функции какой-либо поток не удалит ни один объект.Идиоматично, что объект уничтожается только в
thread()
или в любом потоке, еслиthread() == nullptr
. Поскольку цикл событий потока вызывает функтор, нулевой поток никогда не является проблемой дляb
- без потока функтор не будет вызываться. Увы, нет гарантии о времени жизниa
вb
потоке. Таким образом, безопаснее фиксировать необходимое состояние действия по значению вместо этого, так что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(); });
-
Необработанные указатели на другие объекты могут быть записаны по значению, если вы абсолютно уверены, что время жизни объектов, на которые они указывают, перекрывает время жизни соединения.
static C c; auto p = &c; connect(..., [p]{});
-
Кроме того, для ссылок на объекты:
static D d; connect(..., [&d]{});
-
Не скопируемые объекты, которые не выводятся из
QObject
, должны быть записаны через их общие указатели по значению.std::shared_ptr<E> e { new E }; QSharedPointer<F> f { new F; } connect(..., [e,f]{});
-
QObject
живущие в одной и той же нити могут быть захвачены с помощьюQPointer
; его значение должно быть проверено перед использованием в функторе.QPointer<QObject> g { this->parent(); } connect(..., [g]{ if (g) ... });
-
QObject
, живущие в других потоках, должны быть захвачены общим указателем или слабым указателем. Их родитель должен быть удален до их уничтожения, иначе у вас будут двойные удаления: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) { ... } });