C++智能指针备忘一

http://blog.163.com/modingfa\_002/blog/static/11092546620115895230167/


QT smart point 智能指针  

2011-06-08
09:52:30|  分类:
qt-high-level
|  标签:指针  qt  shared_ptr  std  label  
|字号 订阅

 

 

  1. QPointer (4.0)
     已经不合时宜,能够被QWeakPointer所替代,它不是线程安全的。
  2. QSharedDataPointer (四.0)
     — 提供对数码的COPY-ON-W途胜ITE以及浅拷贝,提供对数据(而不是指向数据的指针)的线程安全的爱护。(注:提供对数据的线程安全维护要整合QsharedData来成功),它是线程安全的。
  3. QSharedPointer (4.5)
       — 完毕了引用计数的可共享能源的强类型指针,它是线程安全的。
  4. QWeakPointer (4.五)
         — 落成了引用计数的可共享财富的弱类型指针,它是线程安全的。
  5. QScopedPointer (四.六)
      — 实现了非引用计数的独享财富的强类型指针,它是线程安全的。

strong pointer :  在有它所指向的能源的全体权时期,永远不会扬弃那一个全部权。 

weak pointer:在有它所针对的能源的全体权时期,允许外界释放其财富从而使其废弃这么些全数权。 

QSharedPointer有着与std::auto_ptr类似的特征,而最大的区分在于它不能够转让全数权而auto_ptr可以。事实上,scoped_ptr永远不可能被复制或被赋值!

 

上面代码应用QSharedPointer,QWeakPointer和QScopedPointer的以身作则:

view
plain
copy
to
clipboard
print?

  1. int main(int argc, char *argv[])  
  2. {  
  3.     QCoreApplication a(argc, argv);  
  4.     //raw pointer  
  5.     QString *p = new QString(“hello”);  
  6.     //Implements non-reference-counted strong pointer  
  7.     QScopedPointer<QString> pScopedPointer(new QString(“Scoped”));  
  8.     // Build error, can NOT be shared and reference-counted  
  9.     //QScopedPointer<QString> pScopedPointer2 = pScopedPointer;  
  10.     //Implements reference-counted strong sharing of pointers  
  11.     QSharedPointer<QString> pSmart(new QString(“Smart”));  
  12.     QSharedPointer<QString> pSmart2;  
  13.     pSmart2 = QSharedPointer<QString>(new QString(“smart 2”));  
  14.     QSharedPointer<QString> pSharedPoninter;  
  15.     // can be shared safely and reference-counted  
  16.     pSharedPoninter = pSmart;  
  17.     qDebug() << *(pSmart.data());  
  18.     qDebug() << *(pSmart2.data());  
  19.     qDebug() << *(pSharedPoninter.data());  
  20.     QTimer *timer = new QTimer();  
  21.     QWeakPointer<QTimer> pWeakPointer = timer;  
  22.     //Weak pointer’s resources can be deleted from outside world  
  23.     delete timer;  
  24.     if (pWeakPointer.isNull())  
  25.     {  
  26.         qDebug() << “contained QObject has been deleted”;  
  27.     }  

 

入门程序

#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对象分配到stack而不是heap中
  • 给label设置标记位Qt::WA_DeleteOnClose

  • 友好调用delete来删除通过new分配到heap中的 label 对象

注:

  • 为了能清楚观看组织和析构函数的调用,我们能够简简单单子类化了1晃QLabel,然后用Label取代后面包车型客车QLabel

    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 模型的特性(之一)
注意:析构时不会delete它管理的资源

 

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

注:

  • MSVC2010 和 GCC g++ 4.3 支持 C++0x
  • MSVC2008 sp1 及 GCC g++ 4.0 支持 tr1

有了那一个东西,大家就足以很不难改造我们前面包车型地铁事例了(只需变更一行):

std::auto_ptr<QLabel> label(new QLabel("Hello Dbzhang800!"));

传闻你所用的Qt的版本,以及C++编写翻译器的帮助程度,你可以选拔:

  • QScopedPointer
  • std::unique_ptr
  • QSharedPointer
  • std::shared_ptr
    • std::tr1::shared_ptr

QPointer

什么样翻译啊?笔者不太理解,保留英文吧。

  • The QPointer class is a template class that provides  guarded
    pointers
      to QObjects.

  • 利用:八个guarded指针,QPointer<T> ,行为和常规的指针 T *
    类似

  • 个性:当其针对性的对象(T必须是QObject及其派生类)被销毁时,它会被自动置NULL.

    • 在意:它本身析构时不会活动销毁所guarded的指标
  • 用途:当你供给保留别的人所负有的QObject对象的指针时,那一点十三分有效

1个例子

     QPointer<QLabel> label = new QLabel;      label->setText("&Status:");      ...      if (label)          label->show();

万一在…部分你将该对象delete掉了,label会自动置NULL,而不会是三个高悬(dangling)的野指针。

QPointer 属于Qt Object模型的骨干机制之一,请留意和别的智能指针的分别。

std::auto_ptr

本条没多少要说的。

  • 无法让五个auto_ptr
    指向同贰个指标!(auto_ptr被灭绝时会自动删除它指向的目的,那样对象会被删去多次)

    • 透过拷贝构造或赋值实行操作时,被拷贝的会自行变成NULL,复制所得的指针将取得能源的唯一全体权
  • 智能指针不可能指向数组(因为其达成中调用的是delete而非delete[])
  • 智能指针无法看做容器类的因素。

在C++0x中,auto_ptr已经不提议利用,以往应该会被别的一个智能指针所替代。

QScopedPointer 与 std::unique_ptr

它们概念上理应是是相同的。下边不再区分:

那是1个很周边auto_ptr的智能指针,它包裹了new操作符在堆上分配的动态目的,可以保障动态成立的靶子在别的时候都能够被科学地删除。但它的全数权越发暴虐,不可能转让,壹旦获得了目的的管理权,你就不可能再从它那里取回来。

无 论是QScopedPointer 还是 std::unique_ptr
都存有3个很好的名字,它向代码的阅读者传递了显眼的音讯:这一个智能指针只可以在本作用域里应用,不期望被转让。因为它的正片构造和赋值操作都以个人的,这一点大家得以对照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 与 std::shared_ptr
行为最周边原始指针,是最像指针的”智能指针”,应用范围比前边的关系的更广。

QSharedPointer 与 QScopedPointer
一样包裹了new操作符在堆上分配的动态指标,但它实现的是引用计数型的智能指针
,能够被轻易地拷贝和赋值,在任意的地点共享它,当未有代码应用(引用计数为0)它时才删除被包裹的动态分配的靶子。shared_ptr也足以高枕无忧地放
到正规容器中,并弥补了std::auto_ptr 和 QScopedPointer
因为更换语义而无法把指针作为容器成分的缺陷。

QWeakPointer 与 std::weak_ptr

强引用类型的QSharedPointer已经不行好用,为啥还要有弱引用的
QWeakPointer?

QWeakPointer 是为合作 QSharedPointer 而引进的壹种智能指针,它更像是
QSharedPointer
的二个帮手(因为它不持有普通指针的作为,未有重载operator*和->)。它的最大职能在于支持QSharedPointer 工作,像3个外人一样来观看能源的利用情况。

  • weak_ptr 首若是为了幸免强引用形成环状。摘自msdn中一段话:
    • A cycle occurs when two or more resources controlled by
      shared_ptr objects hold mutually referencing shared_ptr
      objects. For example, a circular linked list with three elements
      has a head node N0; that node holds a shared_ptr object that
      owns the next node, N1; that node holds a shared_ptr object
      that owns the next node, N2; that node, in turn, holds a
      shared_ptr object that owns the head node, N0, closing the
      cycle. In this situation, none of the reference counts will ever
      become zero, and the nodes in the cycle will not be freed. To
      eliminate the cycle, the last node N2 should hold a weak_ptr
      object pointing to N0 instead of a shared_ptr object. Since the
      weak_ptr object does not own N0 it doesn’t affect N0’s
      reference count, and when the program’s last reference to the
      head node is destroyed the nodes in the list will also be
      destroyed.
  • 在Qt中,对于QObject及其派生类对象,QWeakPointer有异样处理。它能够作为QPointer的替代品
    • 那种情景下,不要求QSharedPointer的留存
    • 效率比 QPointer 高

QSharedDataPointer

那是为协作 QSharedData 完成隐式共享(写时复制
copy-on-write))而提供的有利工具。

Qt中过多的类都使用了隐式共享技术,比如QPixmap、QByteArray、QString、…。而我们为温馨的类完成隐式共享也很不难,比如要兑现多个Employee类:

  • 概念1个只含有3个数目成员(QSharedDataPointer<EmployeeData>)
    的 Employee 类

  • 小编们供给的装有数据成员放置于 派生自QSharedData的 EmployeeData类中。

现实贯彻看 QSharedDataPointer 的马努al,此处略

QExplicitlySharedDataPointer

那是为同盟 QSharedData 达成显式共享而提供的惠及工具。

QExplicitlySharedDataPointer 和 QSharedDataPointer
卓殊类似,但是它禁用了写时复制成效。那使得大家创立的对象更像二个指针。

2个事例,接后边的Employee:

 #include "employee.h"   int main()  {      Employee e1(1001, "Albrecht Durer");      Employee e2 = e1;      e1.setName("Hans Holbein");  }

写时复制技术导致:e一和e二有相同的工号,但有分歧名字。与大家意在的比不上,显式共享能够解决那一个题材,那也使得Employee本人更像2个指南针。

 

顺便看看google编码规范中对三个智能指针的提出:
scoped_ptr
Straightforward and risk-free. Use wherever appropriate.

auto_ptr
Confusing and bug-prone ownership-transfer semantics. Do not use.

shared_ptr
Safe with const referents (i.e. shared_ptr<const T> ).
Reference-counted pointers with non-const referents can occasionally be
the best design, but try to rewrite with single owners where possible.

参考