1、QPointer指针
1.1 QPointer的误区
查看QT的一些书籍会发现,QPointer被认为是一个智能指针,而我们
所理解的智能指针应该如下:
//parent为父对象,可能为空
QPointer<CTest> pTest= new CTest(parent);
之后,对pTestClass是不用delete的了。实际上查看代码后会发现QPointer并非如此的,QPointer的构造和析构只是分别执行了addGuard和removeGuard,再看下去会发现add和remove只是从一个Hash表中删除了CTest这个对象,但是不会delete它。如果我们不断的使用QPointer,而不析构它,实际上会出现内存泄露的,特别是parent为NULL的时候,是没有任何操作会帮你析构new出来的对象的
如果parent不为空呢?
1.2 QT Parent析构问题
如上中parent不为空,或则我们在界面中new QPushButton(parent)等信息,parent会在析构的时候,帮我们析构所有child。但是parent如果没有析构,我们不断new QPushButton(this),程序也会出现内存不断增长的情况,我们不能完全依赖于QT 的Parent机制来解决内存问题
那QT有没有如C++ auto_ptr的智能指针呢
1.3 QScopedPointer
这就是一个我们理解的真正的智能指针了,对象使用完毕,它会帮我们执行delete,方式与QPointer一样,按照如下使用即可
QScopedPointer<CTest> pTest= new CTest(parent); QScopedPointer与auto_ptr的区别在于所有权的转移问题,QScopedPointer刻意设计为不可转移所有权,auto_ptr设置转移后,原指针会失效,会引起误操作。这也是auto_ptr设计的不好的地方,另外要支持所有权的转移并且安全就要用到引用计数的指针了,QT帮我们提供了QSharedPointer。
1.4 QPointer真正实用的地方
C++中指针有个如下问题
CTest* pTest1 = new CTest;
CTest* pTest2 = pTest1;
如果在其它地方
delete pTest1;
我们知道,为了防止野指针,会delete后执行如下语句
pTest1 = NULL,再次使用会判断pTest1是否为空。
可是pTest2怎么办?另外如果有很多pTest3,pTest4怎么办?
QPointer提出了解决此问题的方法,这也是基于所有QT对象都继承自QObject的原因,pTest1析构时会执行到QObject的析构函数中,我们看到析构函数会有如下代码
if (d->hasGuards && !d->isWidget) {
// set all QPointers for this object to zero - note that
// ~QWidget() does this for us, so we don't have to do it twice
QObjectPrivate::clearGuards(this);
}
QT会判断是否有Guard,即我们前面QPointer中执行的addGuard,如果有,会执行clearGuards,即帮我们把pTest2等都置空,这样各处都能使用QPointer::IsNull()来判断并且安全的使用了
1.5 多提一句,涉及到指针离不开上面的几种,而boost也帮我们提供了解决方案,我们应该越来越少的使用delete操作了。从内存泄露中解脱出来
Boost::scoped_pt与QScopedPointer一样
Boost::shared_ptr与QShardPointer一样