QT 指针 源码解析

来源:互联网 发布:java vector实现原理 编辑:程序博客网 时间:2024/04/30 09:56

1、QPointer指针

1.1  QPointer的误区

查看QT的一些书籍会发现,QPointer被认为是一个智能指针,而我们

所理解的智能指针应该如下:

//parent为父对象,可能为空

QPointer<CTest> pTest= new CTest(parent);

之后,对pTestClass是不用delete的了。实际上查看代码后会发现QPointer并非如此的,QPointer的构造和析构只是分别执行了addGuardremoveGuard,再看下去会发现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一样

 

 

0 0