Qt对象树与智能指针结合为何未触发重复删除崩溃?
问题背景
我对Qt对象模型树与智能指针的内存管理机制存在疑惑,编写了一个Qt5测试程序验证情况:
测试代码
child.h
#ifndef CHILD_H #define CHILD_H #include <QObject> #include <QDebug> class Child : public QObject { Q_OBJECT public: explicit Child(QObject *parent = nullptr) : QObject{parent} { qDebug() << "Ctor Child: " << this << ", my parent is -> " << this->parent(); } ~Child() { qDebug() << "Dtor Child: " << this << ", my parent is -> " << this->parent(); } signals: }; #endif // CHILD_H
parent.h
#ifndef PARENT_H #define PARENT_H #include <QObject> #include <QWidget> #include <QSharedPointer> #include <QDebug> #include "child.h" class Parent : public QWidget { Q_OBJECT public: explicit Parent(QWidget *parent = nullptr) : QWidget{parent} , _child{QSharedPointer<Child>::create(this)} { qDebug() << "Ctor Parent: " << this << ", my parent is -> " << this->parent(); } ~ Parent() { qDebug() << "Dtor Parent: " << this << ", my parent is -> " << this->parent(); } signals: private: QSharedPointer<Child> _child; }; #endif // PARENT_H
main.cpp
#include "mainwindow.h" #include "parent.h" #include <QApplication> #include <QList> #include <QDebug> static QList<QSharedPointer<Parent>> myList; int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); for (int i = 1; i <= 2; ++i) { qDebug() << "===== Creation of Parent #" << i << "===="; QSharedPointer<Parent> p{QSharedPointer<Parent>::create()}; p->setObjectName("Parent #" + QString::number(i)); myList.append(p); qDebug() << "========="; } const int value{a.exec()}; qDebug() << "value: " << value; return value; }
程序运行日志
===== Creation of Parent # 1 ==== Ctor Child: Child(0x1118df0) , my parent is -> Parent(0x1101730) Ctor Parent: Parent(0x1101730) , my parent is -> QObject(0x0) ========= ===== Creation of Parent # 2 ==== Ctor Child: Child(0x111d810) , my parent is -> Parent(0x11017f0) Ctor Parent: Parent(0x11017f0) , my parent is -> QObject(0x0) ========= value: 0 Dtor Parent: Parent(0x11017f0, name="Parent #2") , my parent is -> QObject(0x0) Dtor Child: Child(0x111d810) , my parent is -> Parent(0x11017f0, name = "Parent #2") Dtor Parent: Parent(0x1101730, name="Parent #1") , my parent is -> QObject(0x0) Dtor Child: Child(0x1118df0) , my parent is -> Parent(0x1101730, name = "Parent #1")
我的疑惑
程序退出时,静态QList销毁Parent的QSharedPointer,Parent销毁时内部Child的QSharedPointer引用计数归零,自动销毁Child;随后Qt对象树销毁机制会尝试销毁Parent的子对象——也就是已被销毁的Child,按此逻辑应该触发重复删除崩溃,但实际并未发生,想知道原因。
解答
核心原因在于QObject析构函数的自动关联解除逻辑:
当Child被QSharedPointer销毁时,会调用Child的析构函数,进而触发基类QObject的析构函数。QObject的析构函数会执行两个关键操作:
- 将自身从父对象的子对象列表中移除,确保父对象后续销毁时不会再遍历到它。
- 销毁自己的所有子对象(这里
Child没有子对象,所以无影响)。
所以当Parent的析构函数执行到Qt对象树销毁逻辑时,它的子对象列表里已经没有那个被智能指针销毁的Child了,自然不会尝试再次删除它,也就不会出现重复删除的崩溃。
另外需要注意:这种混合使用Qt对象树和智能指针的方式并不推荐,容易引发逻辑混乱。如果选择使用智能指针管理QObject对象,建议不要设置父对象,避免两种内存管理机制的冲突;如果依赖Qt对象树的自动销毁,就不需要额外用智能指针包裹。
内容的提问来源于stack exchange,提问作者anthonyNk
相关产品推荐
相关产品推荐

