标签:proc osi byte 多次 支持 析构函数 stack 弱引用 核心
很简单的入门程序,应该比较熟悉吧 ^_^
#include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello Dbzhang800!"); label->show(); return app.exec(); }
在 从 Qt 的 delete 说开来 一文中,我们提到这个程序存在内存泄露(表现就是析构函数不被调用),而且当时给出了三种解决方法:
给label设置标记位Qt::WA_DeleteOnClose
注:
class Label :public QLabel { public: Label(const QString& text, QWidget *parent=NULL) :QLabel(text, parent){qDebug("from constructor");} ~Label(){qDebug("from destructor");} };
本文中,我们从智能指针(smart pointer)角度继续考虑这个问题
为了管理内存等资源,C++程序员通常采用RAII(Resource Acquisition Is Initialization)机制:在类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。
如果没有智能指针,程序员必须保证new对象能在正确的时机delete,四处编写异常捕获代码以释放资源,而智能指针则可以在退出作用域时(不管是正常流程离开或是因异常离开)总调用delete来析构在堆上动态分配的对象。
我们看看Qt家族的智能指针:
智能指针 |
引入 |
|
QPointer |
Qt Object 模型的特性(之一) |
|
QSharedPointer |
带引用计数 |
Qt4.5 |
QWeakPointer |
Qt4.5 |
|
QScopedPointer |
Qt4.6 |
|
QScopedArrayPointer |
QScopedPointer的派生类 |
Qt4.6 |
QSharedDataPointer |
用来实现Qt的隐式共享(Implicit Sharing) |
Qt4.0 |
QExplicitlySharedDataPointer |
显式共享 |
Qt4.4 |
std::auto_ptr |
|
|
std::shared_ptr |
std::tr1::shared_ptr |
C++0x |
std::weak_ptr |
std::tr1::weak_ptr |
c++0x |
std::unique_ptr |
boost::scoped_ptr |
C++0x |
注:
有了这些东西,我们就可以很容易改造我们前面的例子了(只需改变一行):
std::auto_ptr<QLabel> label(new QLabel("Hello Dbzhang800!"));
根据你所用的Qt的版本,以及C++编译器的支持程度,你可以选用:
如何翻译呢?我不太清楚,保留英文吧。
The QPointer class is a template class that provides guarded pointers to QObjects.
使用:一个guarded指针,QPointer<T> ,行为和常规的指针 T * 类似
一个例子
QPointer<QLabel> label = new QLabel; label->setText("&Status:"); ... if (label) label->show();
如果在...部分你将该对象delete掉了,label会自动置NULL,而不会是一个悬挂(dangling)的野指针。
QPointer 属于Qt Object模型的核心机制之一,请注意和其他智能指针的区别。
这个没多少要说的。
在C++0x中,auto_ptr已经不建议使用,以后应该会被其他3个智能指针所取代。
它们概念上应该是是一样的。下面不再区分:
这是一个很类似auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。但它的所有权更加严格,不能转让,一旦获取了对象的管理权,你就无法再从它那里取回来。
无论是QScopedPointer 还是 std::unique_ptr 都拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让。因为它的拷贝构造和赋值操作都是私有的,这点我们可以对比QObject及其派生类的对象哈。
用法 (来自Qt的manual):
考虑没有智能指针的情况,
void myFunction(bool useSubClass) { MyClass *p = useSubClass ? new MyClass() : new MySubClass; QIODevice *device = handsOverOwnership(); if (m_value > 3) { delete p; delete device; return; } try { process(device); } catch (...) { delete p; delete device; throw; } delete p; delete device; }
我们在异常处理语句中多次书写delete语句,稍有不慎就会导致资源泄露。采用智能指针后,我们就可以将这些异常处理语句简化了:
void myFunction(bool useSubClass) { QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass); QScopedPointer<QIODevice> device(handsOverOwnership()); if (m_value > 3) return; process(device); }
另,我们一开始的例子,也是使用这两个指针的最佳场合了(出main函数作用域就将其指向的对象销毁)。
注意:因为拷贝构造和赋值操作私有的,它也具有auto_ptr同样的“缺陷”——不能用作容器的元素。
QSharedPointer 与 std::shared_ptr 行为最接近原始指针,是最像指针的"智能指针",应用范围比前面的提到的更广。
QSharedPointer 与 QScopedPointer 一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针 ,可以被自由地拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时才删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,并弥补了std::auto_ptr 和 QScopedPointer 因为转移语义而不能把指针作为容器元素的缺陷。
强引用类型的QSharedPointer已经非常好用,为什么还要有弱引用的 QWeakPointer?
QWeakPointer 是为配合 QSharedPointer 而引入的一种智能指针,它更像是 QSharedPointer 的一个助手(因为它不具有普通指针的行为,没有重载operator*和->)。它的最大作用在于协助 QSharedPointer 工作,像一个旁观者一样来观测资源的使用情况。
这是为配合 QSharedData 实现隐式共享(写时复制 copy-on-write))而提供的便利工具。
Qt中众多的类都使用了隐式共享技术,比如QPixmap、QByteArray、QString、...。而我们为自己的类实现隐式共享也很简单,比如要实现一个 Employee类:
定义一个只含有一个数据成员(QSharedDataPointer<EmployeeData>) 的 Employee 类
我们需要的所有数据成员放置于 派生自QSharedData的 EmployeeData类中。
具体实现看 QSharedDataPointer 的Manual,此处略
这是为配合 QSharedData 实现显式共享而提供的便利工具。
QExplicitlySharedDataPointer 和 QSharedDataPointer 非常类似,但是它禁用了写时复制功能。这使得我们创建的对象更像一个指针。
一个例子,接前面的Employee:
#include "employee.h" int main() { Employee e1(1001, "Albrecht Durer"); Employee e2 = e1; e1.setName("Hans Holbein"); }
写时复制技术导致:e1和e2有相同的工号,但有不同名字。与我们期待的不同,显式共享可以解决这个问题,这也使得Employee本身更像一个指针。
标签:proc osi byte 多次 支持 析构函数 stack 弱引用 核心
原文地址:http://www.cnblogs.com/god-of-death/p/7466291.html