1、背景:
在使用信号与槽的时候,槽函数使用的是lambda表达式,但是第五个参数(连接类型)写的是Qt::UniqueConnection。例如:
connect(this, &Dialog::signal_test, this, [=](){
qDebug()<<"coming";
},Qt::UniqueConnection);
然后实际运行发现,此槽函数可以被绑定多次。
2、原因:
1)最直接的解释,可参考QT 关于connect的文档:
Note: Qt::UniqueConnections do not work for lambdas, non-member functions and functors; they only apply to connecting to member functions.
2)调试发现,槽函数为成员函数和lambda时,各自调用的内部函数不一样。
a)成员函数,例如:
connect(this,&Dialog::signal_test,this, &Dialog::TestSlot,Qt::UniqueConnection);
调用的是:
b)lambda表达式,例如:
connect(this, &Dialog::signal_test, this, [=](){
qDebug()<<"coming";
},Qt::UniqueConnection);
调用的是:
而关于QObject::connectImpl中,此函数的第四个参数:
在后续的QObjectPrivate::connectImpl中:
...
if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
if (connections->signalVectorCount() > signal_index) {
const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
while (c2) {
if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
c2 = c2->nextConnectionList.loadRelaxed();
}
}
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
}
...
会去判断slot。
所以成员函数会返回 “return QMetaObject::Connection();”,lambda会继续绑定成功。
3、解决方法:
1)将lambda表达式写成成员函数;
2)人为保障连接的唯一性,即要么在初始化的时候绑定,要么绑定前先调用disconnect。