1. 程式人生 > >27.C++- 智能指針

27.C++- 智能指針

隱式 ++ public auto_ptr val new 文件 weak pre

智能指針

  • 在C++庫中最重要的類模板之一
  • 智能指針實際上是將指針封裝在一個類裏,通過對象管理指針.

STL中的智能指針auto_ptr

頭文件: <memory>

  • 生命周期結束時,自動摧毀指向的內存空間
  • 不能指向堆數組(因為auto_ptr的析構函數刪除指針用的是delete,而不是delete[])
  • auto_ptr的構造函數為explicit類型,所以只能顯示初始化,比如:
  auto_ptr<int> ap1(new int(1));      //初始化正確,創建ap1類模板對象,使類模板裏的指針為int*型,並指向1的地址
  int* p = new int(1);   auto_ptr<int> ap2(p); //初始化正確   // auto_ptr<int> ap3 = new int(2); //出錯,不能隱式初始化
  • 提供get()成員函數,可以用來查看類裏的指針地址.比如:
  auto_ptr<int> ap(new int(1));         
  cout<< ap.get()<<endl;          //打印數值1的地址 : 0x6d2d18
      

  int
*p =ap.get();   cout<< *p<<endl; //打印數值1
  • 一片堆空間只屬於一個智能指針對象(因為多個指向相同地址的智能指針調用析構函數時,會出現bug)
  • 當auto_ptr被拷貝或賦值後,則自身的指針指向的地址會被搶占,比如:
  auto_ptr<int> p1(new int(1));
  auto_ptr<int> p2(new int(2));

  p1 =p2;                                    //首先會delete p1對象的類成員指針,然後將p2對象的類成員指針賦值給p1, 最後修改p2指針地址為NULL
  cout<<"p2 ="<<p2.get()<<endl; //打印 : p2=0   //cout<<*p2<<endl; //出錯,因為p2=0

初探auto_ptr智能指針

#include <iostream>
#include <memory>

using namespace std;

class Test
{
public:
       int mvalue;
       Test(int i=0)
       {
              mvalue=i;
              cout<< "Test("<<mvalue<<")"<<endl;
       }
~Test() { cout<< "~Test("<<mvalue<<")"<<endl; } }; void func() //在func函數裏使用auto_ptr { auto_ptr<Test> p1(new Test(1)); cout<<"p1 ="<<p1.get()<<endl; cout<<endl; auto_ptr<Test> p2(new Test(2)); cout<<"p2 ="<<p2.get()<<endl; cout<<endl; cout<<"p1=p2"<<endl; p1=p2; cout<<endl; cout<<"p1 ="<<p1.get()<<endl; cout<<"p2 ="<<p2.get()<<endl; } int main() { cout<<"*****begin*****"<<endl; func(); cout<<"*****end*****"<<endl; return 0; }

運行打印:

*****begin*****
Test(1)
p1 =0x8db1008

Test(2)
p2 =0x8db1018

p1=p2
~Test(1)

p1 =0x8db1018
p2 =0
~Test(2)
*****end*****

從結果可以看到,由於func()的生命周期結束,所以裏面的auto_ptr指針自動就被釋放了。

可以發現在調用p1=p2時, 首先會delete p1對象的類成員指針(調用~Test(1)析構函數),然後將p2對象的類成員指針賦值給p1(p1=0x8db1018), 最後修改p2指針地址為NULL(p2 =0)

STL中的智能指針shared_ptr(需要C++11支持)

  • 帶有引用計數機制,支持多個指針對象指向同一片內存(實現共享)
  • 提供swap()成員函數,用來交換兩個相同類型的對象,比如:
  shared_ptr<int> p1(new int(1));
  shared_ptr<int> p2(new int(2));

  p1.swap(p2);                  //交換後 p1=2,p2=1

  cout<< *p1 <<endl;            //打印 2
  cout<< *p2 <<endl;            //打印 1

  • 提供unique()成員函數, 判斷該指針對象地址是否被其它指針對象引用
  • 提供get()成員函數,用來獲取指針對象指向的地址
  • 提供reset()成員函數,將自身指針對象地址設為NULL,並將引用計數-1(當計數為0,會自動去delete內存)
  • 提供use_count()成員函數,可以用來查看引用計數個數,比如:
  shared_ptr<int> sp1(new int(30));      //計數+1
  cout<<sp1.use_count()<<endl;           //打印計數:1
  cout<<sp1.unique()<<endl;              //打印:1
  

  shared_ptr<int> sp2(sp1);               //計數+1
  cout<<sp1.use_count()<<endl;            //打印:2
  cout<<sp1.unique()<<endl;               //由於sp1指針對象被sp2引用,打印:0


  sp1.reset();                            //將sp1指針對象地址設為NULL,計數-1

  cout<<sp1.get()<<endl;                  //sp1指針對象地址為NULL,打印:0

  cout<<sp2.use_count()<<endl;            //打印:1

  cout<<sp2.unique()<<endl;               //由於sp1釋放,僅剩下sp2指向30所在的地址,所以打印:1

初探shared_ptr智能指針(以上個Test類為例分析)

#include <iostream>
#include <memory>

using namespace std;

class Test
{
public:
       int mvalue;
       Test(int i=0)
       {
              mvalue=i;
              cout<< "Test("<<mvalue<<")"<<endl;
       }

       ~Test()
       {
              cout<< "~Test("<<mvalue<<")"<<endl;
       }
};

int main()
{  
       cout<<"*****begin*****"<<endl;

       shared_ptr<Test> p1(new Test(1));
       shared_ptr<Test> p2(p1);

       cout<<"*p1="<< p1->mvalue<<","<<"*p2="<<p2->mvalue<<endl;

       p1.reset();
       p2.reset();     

       cout<<"count:"<<p2.use_count()<<endl;

       cout<<"*****end*****"<<endl;
       return 0;
}

運行打印:

*****begin*****
Test(1)
*p1=1, *p2=1
~Test(1)
count:0
*****end*****

從結果可以看到,我們把p1和p2都釋放了後,由於count=0,便自動去delete Test指針了.

STL中的其它智能指針(在後面學習到,再來深入描述)

-weak_ptr

  • 配合shared_ptr而引入的一種智能指針

-unique_ptr

  • 只能一個指針對象指向一片內存空間(和auto_ptr類似),但是不能被拷貝和賦值(實現唯一性)

QT中的智能指針(在後面學習到,再來深入描述)

-QPointer

頭文件<QPointer>

  • 當其指向的對象被銷毀時,他會被自動置空(避免被多次釋放和野指針)
  • 缺點在於,該模板類析構時,不會自動摧毀所指向的對象(需要手工delete)

-QSharedPointer

頭文件<QSharedPointer>

  • 帶有引用計數機制,支持多個指針對象指向同一片內存(實現共享)
  • 可以被自由地拷貝和賦值
  • 當引用計數為0(最後一個指針被摧毀)時,才刪除指向的對象(和shared_ptr類似)

27.C++- 智能指針