# QT中的内存管理 > **调用析构函数与操作系统主动回收内存的区别** > > 当程序的生命周期结束时,操作系统会直接回收所有程序占用的内存,并且不调用析构函数。这可能导致一些预料之外的情况。 > > ​ 比如强制关闭编辑器会导致编辑器的最近更改消失。 ## Qt对象树 ​ Qt中的所有可见控件都继承自`QObject`类。因此,Qt通过`QObject`类构建了一个对象树,用于方便Qt GUI程序的内存管理。 ​ 当创建一个`QObject`对象时,可以为其制定一个父对象。这时,该`QObject`对象被添加到父对象的`children()`列表中。当该`QObject`对象被析构时,将自动从`children()`列表中删除自己,而当父对象析构时,其`children()`列表中的所有子对象都将被析构。 > 注意:这里的父类和子类不是指继承上的,而是指对象权限:父类可以控制子类的生命周期,而子类只能控制自己的生命周期。 ​ 利用Qt的这个特性,可以在结束一个窗口时,只`delete`父对象的指针。 > 标准C++对象析构的顺序是:以与声明顺序相反的顺序调用对象的析构函数(堆上的对象的生命周期取决于程序员)。 **父对象的指定** 实现看下面一段代码: ```c++ void f(){ QWidget window; QPushButton quit("Quit",&window); } ``` ​ 当该函数结束运行时,按照标准C++的析构顺序,实现析构`quit`,此时,`quit`将会自动从`window`的`children()`列表中删除,然后析构`window`,代码没有任何错误。 第二段代码: ```c++ void f(){ QPushButton quit("QUit"); QWidget window; quit.setParent(&window); } ``` ​ 当该函数结束时,实现调用`window`的析构函数,此时,**window自动调用quit的析构函数**。然后C++调用`quit`的析构函数。也就是说,`quit`被析构了两次。 **因此,为了不再开发中出现意料之外的小毛病,尽量在创建对象时就指定父对象** ## Q&A ​ 博主你说“在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。”,可是您又在《hello world》中拒了一个在堆上创建QLabel的反例。求解惑。 > 在 main() 函数中,不应该在堆上面创建对象。这是由于如果在 main() 中在堆上面创建对象,app.exec() > 函数是一个死循环,创建出的这个对象没有办法被 delete(不开启事件循环,组件就不能显示,不显示组件就不能 > delete,否则你还创建它干什么呢?)。另外的原因是,由于我们的 QApplication 是在栈上面创建的,在堆上面创建的 QLabel > 对象生命周期要长于 QApplication,这在 Qt 中是应该避免的。而对于我们自己定义的组件就没有这个问题,因为不在 main() > 函数中,我们始终可以保证最晚在关闭时销毁(当然是不发生内存泄露的情况下),也就没有这个问题。 ​ 你说的这句话我不是很理解“另外的原因是,由于我们的 QApplication 是在栈上面创建的,在堆上面创建的 QLabel 对象生命周期要长于 QApplication,这在 Qt 中是应该避免的。而对于我们自己定义的组件就没有这个问题,因为不在 main() 函数中,我们始终可以保证最晚在关闭时销毁(当然是不发生内存泄露的情况下),也就没有这个问题。” 为什么我们自己定义的组件不在 main() 函数中,可以解释一下吗? 谢谢! > 我们自己定义的组件不在 main() 函数直接被调用,而是通过 MainWindow 之类的顶层窗口调用,而 MainWindow 通常直接被 > main() 实例化。因此,只要保证了最顶层的 MainWindow 能够正确释放,并且 parent > 能够连接成链,就可以保证每一个组件被正确释放。