我有一个使用Qt的C++程序,带有一个GUI QObject,它有一个链接到函数(bar()
)的ComboBox(我们称之为foo
)。这个QObject称为对象A
。
组合框在构造函数中链接:
connect(foo, SIGNAL(currentIndexChanged(int)), SLOT(bar(int)));
在bar(int)
中,这个函数在函数的末尾被调用:
inspector->update();
在检查器的update
功能中,会发生以下情况:
A
被删除(delete A;
,几乎 - 它是用new
创建的)。创建一个与
A
类型相同的新实例,我们称之为对象B
。
这是初始化的,运行正常片刻,然后一切都变得非常糟糕。
程序出现段错误,但只是由于 Qt 错误。GDB 没有多大帮助,但通过 Valgrind memcheck 运行程序会产生大量无效读取,如下所示:
==23410== Invalid read of size 8
==23410== at 0xFE92D7A: QMetaObject::activate(QObject*, int, int, void**) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.9.5)
==23410== by 0x79DDC94: QComboBox::currentIndexChanged(QString const&) (in /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5.9.5)
==23410== by 0x79DFB2D: ??? (in /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5.9.5)
...
==23410== Address 0x3218ca68 is 8 bytes inside a block of size 48 free'd
==23410== at 0x4C3123B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==23410== by 0xFE9119A: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.9.5)
==23410== by 0x7913D4B: QWidget::~QWidget() (in /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5.9.5)
在我看来,这似乎是来自foo
的信号再次发送,并试图调用不存在的对象A
bar()
。但这怎么可能呢?当然,delete A
也应该阻止任何信号通过?另外,我只更改一次组合框的值 - 为什么要发送多个信号?
我尝试过阻止信号,也尝试重新排列,但没有成功。
这是整个相关的Valgrind memcheck日志。
这是Qt的错误吗?还是我做错了什么?非常感谢任何帮助,包括进一步调试的帮助。
尝试这样做:
-
首先向班级添加成员
QMetaObject::Connection foo_barConnect;
。 -
在构造函数中,将
connect
保存在foo_barConnect
:
foo_barConnect = connect(foo, SIGNAL(currentIndexChanged(int)), SLOT(bar(int)));
- 在
update()
函数中,在delete
之前添加:
// Check if `foo_barConnect` is valid (connected)
if(foo_barConnect){
// Disconnect foo_bar connection
disconnect(foo_barConnect);
}
- 如果您重新
new
对象并且需要连接,请不要忘记重新connect
并将连接存储在foo_barConnect
中。
希望对您有所帮助。