27.C++- 智能指針
阿新 • • 發佈:2018-04-11
隱式 ++ 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指針地址為NULLcout<<"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++- 智能指針