You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt对象树与智能指针结合为何未触发重复删除崩溃?

Qt对象树与QSharedPointer混合内存管理的疑问解答

问题背景

我对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的析构函数会执行两个关键操作:

  1. 将自身从父对象的子对象列表中移除,确保父对象后续销毁时不会再遍历到它。
  2. 销毁自己的所有子对象(这里Child没有子对象,所以无影响)。

所以当Parent的析构函数执行到Qt对象树销毁逻辑时,它的子对象列表里已经没有那个被智能指针销毁的Child了,自然不会尝试再次删除它,也就不会出现重复删除的崩溃。

另外需要注意:这种混合使用Qt对象树和智能指针的方式并不推荐,容易引发逻辑混乱。如果选择使用智能指针管理QObject对象,建议不要设置父对象,避免两种内存管理机制的冲突;如果依赖Qt对象树的自动销毁,就不需要额外用智能指针包裹。


内容的提问来源于stack exchange,提问作者anthonyNk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:17:33