分享

Qt内存管理-总结

 just_person 2012-10-17

以前研究过Qt内存回收的机制,现在做一下总结:

总结的说法是:所以继承与QObject的类,并设置了parent(在构造时,或用setParent函数,或parent的addChild相关信息),所以在parent被delete时,这个parent的相关所有child都会自动delete,不用用户手动处理。

根据上面的说法,会出现三个问题:

1.当child被delete时parent怎么知道?

2.parent怎么区分它的child是new出来的,还是不是new的。

3.当parent被delete后,child怎么知道自己被delete了。

我们慢慢来回答:

第一个问题,parent是用一个数给来保存childs的指针的,当一个child被销毁时,child的析构函数会调用parent并把parent的指针数据中自己对数的值改为0,那么最后是0的指不管多少次都无所谓了。

第二个问题,parent还真TMD的不区别它的child是不是new出来的,只要是它的child,它在销毁时就直接delete才不管你是不是new出来的,这时就体现出了delete的强大,delete可以释放掉任何的对象(调用它的析构函数)和内存。注意:这么操作存在一个很大的问题。

第三个问题,child还真不知道它自己是否被delete掉了。野指针出现了吧。


最后我们还要考虑,第二个问题和第三个问题的处理方法:

当delete出一个不是new出来的对象后,编译器可不认帐,不会认为这个对象已经被销毁了,在这个对象的生命周期结束时,程序还会再调用一次这个类的析构函数,出错了吧,一个美好的段错误。为了防止这种情况的出现,我们要防止在非new的child对象结束使用之前销毁parent。在正确的QT开发中,顶级的patent一般是在main函数中,而patent生命周期一般都会比child长,所以正常都不会出错,只要我们编码注意不要写出如下代码:

{

QObject*parent=newQObject(0);
QObjectchild(parent);
delete parent;

}

上面代码中parent的生命周期比child短,当然如果你代码中有一个child是static的,那我也救不了你。

第三个问题,Qt不建议在一个parent的范围之外持有对childs的指针,按它说的当然不会出野指针的问题了。但是非要在parent外持有child的指针,那么Qt推荐使用QPointer,QPointer相当于一个智能指针,不用智能指针前的代码如下:

{

QObject*parent=newQObject(0);
QObject*child=newQObject(parent);
deleteparent;
child->...

}

第四步操作就会同错了,如果用了QPointer的代码如下

{

QObject*parent=newQObject(0);
QObject*child=newQObject(parent);
QPointer<QObject>p=child;
deleteparent;
if(p.isNull()){
p->...
}

}

在使用之前判断是否为空,这时就不会再出错段错误了。

最后我们大致来说一下QPointer的现实原理,在QPointer保存了一个QObject的指针,并把这个指针的指针(双指针)交给全局变量 GuardHash 管理,而QObject 在销毁时(析构函数,QWidget是通过自己的析构函数的,而不是依赖QObject的)会调用QObjectPrivate::clearGuards 函数来把全局 GuardHash 的那个双指针置为*零,因为是双指针的问题,所以QPointer中指针当然也为零了。用isNull 判断就为空了。

Qt这块东西实现的还真是有点复杂啊。但给我们开发中内存管理这一块省了不少麻烦。

最后补充一个问题:当一个QOBJECT正在接受事件队列时如果中途被你销毁掉了,就是出现问题了,所以QT中建议大家不要直接DELETE掉一个QOBJECT,如果一定要这样做,要使用QOBJECT的deleteLater()函数,它会让所有事件都发送完一切处理好后马上清除这片内存,而且就算调用多次的deletelater也不会有问题。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多