在Qt中,当你将一个对象设置为另一个对象的子对象时,Qt会自动管理它们的生命周期,包括子对象在堆上分配的内存空间。这意味着,如果你使用 new 在堆上创建了一个子对象,并将其设置为另一个对象的子对象,当父对象被销毁时,Qt会自动删除子对象并释放其内存空间,以避免内存泄漏。

QT中对象的基类是QObject,其构造函数为实例传入父指针,同时提供children()函数返回QObjectList获取所有子对象。这是QT的内存管理机制,创建一个QObject对象时,其会被添加到其父对象的子列表中,当父对象析构时,其子对象列表中的所有对象会被析构。此外,析构子对象会对应删除父对象子列表中的对应项。

这是为了应对在某个控件下new新的空间后没有及时delete的情况,在对象树结构下,父控件销毁时,子空间及布局管理器会被一并销毁。但是如果构造时的父对象为null,就需要对应的手动delete。

问题

C++中的析构按照构造相反的顺序,如果先创建子对象,再创建父对象,使用set方法把子对象加入父对象内,在这种情况下析构时,析构函数会先析构父对象子列表中的所有子对象,再析构父对象,再析构子对象。此时子对象已经被析构,所以会导致程序崩溃。

#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QPushButton btn("button");
    QWidget widget;
    btn.setParent(&widget);
    widget.show();

    return a.exec();
}

结论

QT对象树机制无疑是内存管理的有效手段,但其使用需要规范:

  • 先创建父对象,再创建子对象,子对象创建时指示父对象;
  • 尽量在堆上创建子对象(避免父控件子列表悬空指针);参考:堆和栈上对象创建的区别
  • QObject不能使用static修饰(保证QObject对象在QApplication创建后创建、销毁前销毁)
03-27 18:40