文章目录
一、前言
可以看到上述代码中,new的对象没有手动释放,其原理就是对象树。
二、什么是对象树
下图是一个对象树,win是窗口,Topic、obj是小控件。
三、8注意
(1)
不是继承关系中的子类父类。这里的措辞是对象,指对象与对象之间的树状关系,是父对象与子对象的关系。
(2)
一个父对象可以包含多个子对象,但一个子对象只有一个父对象(原理:根据下图Qt帮助文档可知)
(3)
指定父对象(如btn->setParent(this),创建的这个QObject对象btn自动添加到父对象的children()列表)后,子对象就不需要手动释放。未指定的需要手动释放,否则出现内存泄露。
(4)
当父对象析构时,其子对象列表children()中所有的对象被析构。当子对象先析构时,子对象自动从父对象的children()列表删除。
堆区:首先delete掉对应对象空间,其子对象按顺序调用析构函数,父对象析构函数不会再调用,如下图
栈区:不允许delete
(5)
析构≠释放。
这里要和C++区分:在C++中,不存在继承关系时,按照创建顺序,先创建的先构造,先构造的后析构,如下图
存在继承关系时,父类先构造,后析构,如下图
在Qt中,不存在对象树时:构造析构顺序和C++不存在继承关系时一样,按照创建顺序,先创建的先构造,先构造的后析构。
①若在堆开辟空间,则先创建的先构造先析构,唯一要注意的就是销毁过程相反(即执行某个QObject对象的析构函数时还没有释放内存,在析构函数结束时才释放,这里常常产生错觉);
②若在栈开辟空间,则先创建后释放。
堆区,如下图:
栈区,如下图:
(6)
正常情况(不使用delete、无父对象子对象创建顺序问题)栈区内存释放过程:先创建后析构。如下图
(7)
正常情况堆区内存释放过程:用下图案例说明,从根节点开始(即最顶层父对象w1),程序中w1.show()显示窗口(w2、w3、w4包含在里面),这时候点击关闭按钮触发w1窗口的close()槽,进入w1的析构函数,首先执行w1析构函数内的qDebug()宏,输出信息“w1析构”(注意这时候w1还没有被释放),接着查看w1是否有子对象,发现有子对象w2,则继续进入w2的析构函数,输出信息“w2析构”,同理,进入w3析构函数,输出信息“w3析构”,最后进入w4的析构函数,输出信息“w4析构”,发现w4没有子对象,开始回走,首先结束w4析构函数,这时候才释放w4内存空间,接着释放w3,…,直到释放完全。如下图
(8)
QWidget是QObject的子类,在parent机制上无区别,但在实际使用时QWidget更复杂,原因是QWidget和QEventLoop高度配合才能完成工作。实际中,QWidget的关闭流程,首先用户点击关闭按钮触发close()槽,然后Qt向widget发送QCloseEvent,默认的QCloseEvent(用户没有重写,使用默认)将widget隐藏起来,即hide()。所以,通过QWidget关闭流程可知,Widget关闭的实质是隐藏,而没有释放内存。因此,需要设置Qt::WA_DeleteOnClose属性,使得close后调用widget的析构函数,另外一种就是直接手动delete。
四、2缺陷
(1)
上面说到先构造后析构(C++原理),即先创建后析构。有一种情况,先创建子对象,后创建父对象。
对于在栈区开辟空间的情况,根据第一句所说则应该先析构父对象,又遵从Qt对象树原理,则其子对象随之被析构,代码继续执行,按照第一句所说则会再析构一次子对象,这时出现对同一对象调用两次析构函数的情况,而C++中不允许重复调用两次析构函数,因此程序崩溃。如下图,关闭w1后程序crush
对于在堆区开辟空间的情况:子对象和父对象的创建先后无影响
(2)
由注意的(4)可知delete很危险。
五、析构顺序总结
(1)使用delete
堆区:delete的对象及其所有子对象,按顺序从父对象到子对象调用析构函数。(与创建顺序无关)
栈区:不允许delete。
(2)先创建子对象,后创建父对象
堆区:先创建先析构,但最后释放内存,也就是先析构子对象。
栈区:不允许,应用程序crush。
(3)正常情况(不使用delete、无父对象子对象创建顺序问题)
堆区:先析构父对象,但子对象先释放内存。
栈区:先创建后析构,也可以理解为先析构子对象后析构父对象,析构的同时释放内存。
六、1迷惑
不要把Qt和C++完全等比,正常情况下在堆区开辟的对象,其析构函数被调用时不会释放对象空间,即先创建的先调用析构函数,但是最后释放(等调用到最底层子对象结束后开始往回走,一个一个结束析构函数,这时候才真正的释放内存)。
七、针对上述,我们可以
①先创建父对象后创建子对象
②在堆上创建对象
③不要对指定了父对象的对象delete
八、文档
后续补上。
转载注明出处 |
---|