C++ 智能指針類 auto_ptr shared_ptr weak_ptr

出處:http://blog.csdn.net/heyabo/article/details/8791410

這篇文章主要來源於:codeguru網站的一篇文章:A TR1 tutorial:smart pointer  (詳細介紹了C++的智能指針,尤其是shared_ptr)。
眾所周知,在 TR1 之前,C++標準庫中的智能指針只有auto_ptr,但由於它的【排他所有權模式】(exclusive ownership model)導致了許多問題,為解決,C++TR1中引入了 boost 開源庫中的智能指針:shared_ptr 和 weak_ptr 並使之成為了標準庫的一部分(C++11標準)。
注1C++ TR1 即 C++ Technical Report 1 是 ISO/IEC TR 19768, C++ Library Extensions(函數庫擴充)的一般名稱,它是針對 C++ 標準庫的第一次擴展。
注2:C++最新標準:C++11已將智能指針:shared_ptr、weak_ptr收錄為標準庫中,即對應為:std::shared_ptr, std::weak_ptr,相應的頭文件:<memory>(相比TR1:頭文件:<tr1/memory>).
注3若讀者編譯器不支持C++11標準,則編譯時:1.將頭文件由<memory> 改為 <tr1/memory>; 2.將namespace由 std:: 改為 std::tr1 .

一、智能指針類:std::auto_ptr

由於 auto_ptr 基於【排他所有權模式】,這意味著:兩個指針(同類型)不能指向同一個資源,複製或賦值都會改變資源的所有權。
一個簡單的例子1
  1. #include <iostream>    
  2. #include <memory>    
  3. class A    
  4. {    
  5. public:    
  6.     void print(){std::cout<<“A::print”<<std::endl;}    
  7. };    
  8. int main()    
  9. {    
  10.     std::auto_ptr<A>pa1(new A);    
  11.     pa1->print();    
  12.     std::cout<<“pa1 pointer:”<<pa1.get()<<std::endl;    
  13.     
  14.     std::auto_ptr<A>pa2(pa1); //copy constructor    
  15.     pa2->print();    
  16.     std::cout<<“pa1 pointer:”<<pa1.get()<<std::endl;    
  17.     std::cout<<“pa2 pointer:”<<pa2.get()<<std::endl;    
  18.     
  19.     return 0;    
  20. }  


輸出

即即經過複製構造之後,pa1所指向資源的所有權轉向了pa2,而pa1變成空,二者不能同時共享該資源。
auto_ptr 主要有兩大問題
  • 複製和賦值會改變資源的所有權,不符合人的直覺。
  • 在 STL 容器中無法使用auto_ptr ,因為容器內的元素必需支持可複製(copy constructable)和可賦值(assignable)。

二、C++11中新增的智能指針

新加入標準模板庫(STL)的智能指針有兩個:
shared_ptr:基於引用計數模型。每次有 shared_ptr 對象指向資源,引用計數器就加1;當有 shared_ptr 對象析構時,計數器減1;當計數器值為0時,被指向的資源將會被釋放掉。且該類型的指針可複製和可賦值,即其可用於STL容器中。此外,shared_ptr 指針可與多態類型和不完全類型一起使用。主要缺點:無法檢測出循環引用(後面會細說),如一顆樹,其中既有指向孩子結點的指針又有指向父親結點的指針,即孩子父親相互引用。這會造成資源無法釋放,從而導致內存洩露。為了 fix 這個問題,引入了另一個智能指針:weak_ptr.
weak_ptr:指向有shared_ptr 指向的資源(即其需要shared_ptr的參與,其輔助 shared_ptr 之用),但是不會導致計數。一旦計數器為0,不管此時指向資源的 weak_ptr 指針有多少,資源都會被釋放,而所有的這些 weak_ptr 指針會被標記為無效狀態(即 weak_ptr作為觀察shared_ptr 的角色存在著,shared_ptr 不會感受到 weak_ptr 的存在)。
上一例子的shared_ptr 實現-例子2
  1. #include <iostream>  
  2. #include <memory>  
  3. class A  
  4. {  
  5. public:  
  6.     void print(){std::cout<<“A::print”<<std::endl;}  
  7. };  
  8. int main()  
  9. {  
  10.     std::shared_ptr<A>sp1(new A); //namespace: std::  
  11.     sp1->print();  
  12.     std::cout<<“sp1 pointer:”<<sp1.get()<<std::endl;  
  13.   
  14.     std::shared_ptr<A>sp2(sp1); //copy constructor  
  15.     sp2->print();  
  16.     std::cout<<“sp1 pointer:”<<sp1.get()<<std::endl;  
  17.     std::cout<<“sp2 pointer:”<<sp2.get()<<std::endl;  
  18.   
  19.     std::cout<<“count sp1:”<<sp1.use_count()<<std::endl; //get reference count  
  20.     std::cout<<“count sp2:”<<sp2.use_count()<<std::endl;  
  21.   
  22.     return 0;  
  23. }  


輸出


可知:sp2創建後,sp1對資源的所有權並沒有被剝奪,而是sp1 和 sp2 均指向了資源,且此時資源的引用計數為2。當兩個shard_ptr 指針sp1、sp2 超過其作用域時,最後一個析構的指針將會致使資源的釋放(因為引用計數為0了)。

三、智能指針類:std::tr1::shared_ptr


3.1 概念

std::shared_ptr 智能指針共享所指向的資源(所有權),即幾個 shared_ptr 可同時擁有一個對象,且共享一個控制塊(constrol block),包含指向資源的 shared_ptr對象個數、指向資源的 weak_ptr 對象個數以及刪除器(deleter:用戶自定義的用於釋放資源的函數,可以默認沒有)。
一個空的 shared_ptr 對象不擁有任何資源和控制塊。另一方面,一個 shared_ptr 初始化為一個NULL 指針和一個控制塊,這有別有空的 shared_ptr。當共享的引用計數器為0時,資源釋放(delete 操作符釋放,或由用戶提供的 刪除器 釋放它)。

3.2 使用


(1)創建一個 shared_ptr 對象

常見,一個 shared_ptr 對象可由以下四種對象來構造
  • 指向任何類型 T 的指針(包括 const T),也可為指向的資源指定刪除器釋放它;
  • 另一個 shared_ptr 對象;
  • 一個 weak_ptr 對象;
  • 一個 auto_ptr 對象。
它們對應的構造函數如下:
  1. //1  
  2. template<class T>  
  3. explicit shared_ptr(T*);  
  4. template<class T, class D>  
  5. shared_ptr(T*, D);  
  6. //2  
  7. template<class T>  
  8. shared_ptr(const shared_ptr<T>&);  
  9. //3  
  10. template<class T>  
  11. shared_ptr(const weak_ptr<T>&);  
  12. //4  
  13. shared_ptr(const auto_ptr&);  


(2)刪除器(deleter)與 get_deleter函數:

get_deleter函數返回一個指針,指向shared_ptr 的刪除器,如果沒有提供刪除器則返回0。
例子3
  1. #include <iostream>  
  2. #include <memory>  
  3. class A  
  4. {  
  5. public:  
  6.     static A* alloc()  
  7.     {  
  8.         A* pa = new A;  
  9.         std::cout<<“a new object was created”<<std::endl;  
  10.         return pa;  
  11.     }  
  12.     static void free(A* pa)  
  13.     {  
  14.         delete pa;  
  15.         std::cout<<“A object was destroyed”<<std::endl;  
  16.     }  
  17. };  
  18. typedef void(*deleter)(A*); //define a function type pointer to free;  
  19. int main()  
  20. {  
  21.     std::shared_ptr<A> spa(A::alloc(), &A::free);//deleter: &A::free()  
  22.   
  23.     deleter* del = std::get_deleter<deleter>(spa);  
  24.     std::cout<<“get_deleter(spa)!=0 == “<<std::boolalpha<<(del!=0)<<std::endl;  
  25.     return 0;  
  26. }  


輸出


(3)-> 、 * 操作符和 get 函數

shared_ptr 類重載了-> 操作符和 * 操作符,前者返回指向資源的指針;後者指向資源的引用。故無需內部指針。其原型如下:
  1. template<class T>  
  2. class shared_ptr  
  3. {  
  4. public:  
  5.     T* get() const;  
  6.     T& operator*()const;  
  7.     T* operator->()const;  
  8. };  


其中 get 函數返回指向資源的指針,基本等同於 ->操作符,且與auto_ptr 兼容。

例子4
  1. #include <iostream>  
  2. #include <memory>  
  3. class A  
  4. {  
  5. public:  
  6.     void print(){std::cout<<“A::print”<<std::endl;}  
  7. };  
  8. int main()  
  9. {  
  10.     std::shared_ptr<A> sp(new A);  
  11.     A* pa = sp.get();  
  12.     if(pa)pa->print();  
  13.     std::cout<<“-> operator: “;  
  14.     sp->print();  
  15.     std::cout<<“* operator: “;  
  16.     (*sp).print();  
  17.   
  18.     return 0;  
  19. }  


輸出


(4)條件操作符(bool operator)

shared_ptr 類提供了布爾操作符,允許 shared_ptr 對象用於布爾表達式去檢查是否該shared_ptr對象裡的指針為NULL。
例子5
  1. #include <iostream>  
  2. #include <memory>  
  3. #include <string>  
  4. int main()  
  5. {  
  6.     std::shared_ptr<std::string> sp1;  
  7.     if(sp1)  
  8.     {  
  9.         std::cout<<“pointer in sp1 is not NULL”<<std::endl;  
  10.     }  
  11.     else  
  12.     {  
  13.         std::cout<<“pointer in sp1 is NULL”<<std::endl;  
  14.     }  
  15.   
  16.     std::shared_ptr<std::string> sp2(new std::string(“hello world”));  
  17.     if(sp2)  
  18.     {  
  19.         std::cout<<“pointer in sp2 is not NULL”<<std::endl;  
  20.     }  
  21.     else  
  22.     {  
  23.         std::cout<<“pointer in sp2 is NULL”<<std::endl;  
  24.     }  
  25.   
  26.     return 0;  
  27. }  


輸出


(5)交換與賦值(Swap and assignment)


I、函數原型:void swap(shared_ptr& r); //交換*this 與 r 的內容
II、賦值操作符:operator= ,重載後可將shared_ptr 或 auto_ptr 對象賦值給 shared_ptr 對象。
原型如下:
  1. template<class T>  
  2. shared_ptr& operatork=(const shared_ptr<T>&r);  
  3. template<class T>  
  4. shared_ptr& operator=(const std::auto_ptr<T>& r);  
  5. };  


例子6

  1. #include <iostream>  
  2. #include <memory>  
  3. #include <string>  
  4. void isEmpty(std::shared_ptr<std::string>& r)  
  5. {  
  6.     if(r)  
  7.     {  
  8.         std::cout<<“pointer in shared_ptr is not NULL”<<std::endl;  
  9.     }  
  10.     else  
  11.     {  
  12.         std::cout<<“pointer in shared_ptr is NULL”<<std::endl;  
  13.     }  
  14.   
  15. }  
  16. int main()  
  17. {  
  18.     std::cout<<“before swap:”<<std::endl;  
  19.     std::shared_ptr<std::string> sp1;  
  20.     std::cout<<“sp1: “;  
  21.     isEmpty(sp1);  
  22.     std::shared_ptr<std::string> sp2(new std::string(“hello world”));  
  23.     std::cout<<“sp2: “;  
  24.     isEmpty(sp2);  
  25.   
  26.     sp1.swap(sp2); //swap  
  27.     std::cout<<“after swap:”<<std::endl;  
  28.     std::cout<<“sp1: “;  
  29.     isEmpty(sp1);  
  30.     std::cout<<“sp2: “;  
  31.     isEmpty(sp2);  
  32.     std::cout<<“before operator=:”<<std::endl;  
  33.     std::cout<<“sp1: “<<sp1<<“, *sp1: “<<*sp1<<std::endl;  
  34.     std::cout<<“sp2: “;  
  35.     isEmpty(sp2);  
  36.     sp2 = sp1; //assignment  
  37.     std::cout<<“after operator=:”<<std::endl;  
  38.     std::cout<<“sp1: “<<sp1<<“, *sp1: “<<*sp1<<std::endl;  
  39.     std::cout<<“sp2: “<<sp2<<“, *sp2: “<<*sp2<<std::endl;  
  40.   
  41.     return 0;  
  42. }  


輸出


(6)unique 與 use_count函數


函數原型
  1. //use_count  
  2. long use_count() const; //返回所有指向共享資源的shared_ptr 指針對象的個數  
  3.   
  4. //unique()  
  5. bool unique() const; //檢查是否當前只有一個share_ptr 指針指向共享的資源。等價於:use_count() == 1  


例子7

  1. #include <iostream>  
  2. #include <memory>  
  3. #include <string>  
  4. int main()  
  5. {  
  6.     std::shared_ptr<std::string> sp1(new std::string(“hello world”));  
  7.     std::cout<<“unique:”<<std::boolalpha<<sp1.unique()<<std::endl;  
  8.     std::cout<<“count:”<<sp1.use_count()<<std::endl;  
  9.   
  10.     std::shared_ptr<std::string> sp2(sp1);  
  11.     std::cout<<“unique:”<<std::boolalpha<<sp1.unique()<<std::endl;  
  12.     std::cout<<“sp1 count:”<<sp1.use_count()<<std::endl;  
  13.     std::cout<<“sp2 count:”<<sp2.use_count()<<std::endl;  
  14.   
  15.     return 0;  
  16. }  


輸出


(7)reset函數


函數原型
  1. //std::shared_ptr::reset  
  2. void reset();  
  3.   
  4. template<class Y>  
  5. void reset(Y* ptr);  
  6.   
  7. template<class Y, class Deleter>  
  8. void reset(Y* ptr, Deleter d);   


該函數用 ptr 指針指向的資源替換掉當前shared_ptr 管理的資源,使 shared_ptr對象管理新的資源(pointered by ptr),以前資源對應的share_ptr 對象的引用計數減1。如果reset函數的參數為空,則表示*this(當前share_ptr 對象)退出共享資源。

例子8:
  1. #include <iostream>  
  2. #include <memory>  
  3. class A  
  4. {  
  5. private:  
  6.     int m_x;  
  7. public:  
  8.     explicit A(int x =0):m_x(x){}  
  9.     int getX(){return m_x;}  
  10.     int setX(int x){m_x = x;}  
  11.     void print(){std::cout<<“A::print”<<std::endl;}  
  12.     static A* alloc(int x)  
  13.     {  
  14.         A* pa = new A(x);  
  15.         std::cout<<“a new object was created”<<std::endl;  
  16.     }  
  17.     static void free(A* pa)  
  18.     {  
  19.         std::cout<<“x: “<<pa->getX();  
  20.         delete pa;  
  21.         std::cout<<“,A object was destroyed”<<std::endl;  
  22.     }  
  23. };  
  24. int main()  
  25. {  
  26.     std::shared_ptr<A> sp1(new A(10),&A::free);  
  27.     std::shared_ptr<A> sp2(sp1);  
  28.     std::shared_ptr<A> sp3(sp1);  
  29.     std::cout<<“sp1 x :”<<sp1->getX()<<std::endl;  
  30.     std::cout<<“sp2 x :”<<sp2->getX()<<std::endl;  
  31.     std::cout<<“sp3 x :”<<sp3->getX()<<std::endl;  
  32.     std::cout<<“sp1 count:”<<sp1.use_count()<<std::endl;  
  33.     std::cout<<“sp2 count:”<<sp2.use_count()<<std::endl;  
  34.     std::cout<<“sp3 count:”<<sp3.use_count()<<std::endl;  
  35.   
  36.     sp1.reset();  
  37.     A* pa = new A(20);  
  38.     sp2.reset(pa,&A::free);  
  39.     std::cout<<“after reset:”<<std::endl;  
  40.     if(NULL == sp1)  
  41.     {  
  42.         std::cout<<“pointer in sp1 is NULL”<<std::endl;  
  43.     }  
  44.     //std::cout<<“sp1 x :”<<sp1->getX()<<std::endl;  
  45.     std::cout<<“sp2 x :”<<sp2->getX()<<std::endl;  
  46.     std::cout<<“sp3 x :”<<sp3->getX()<<std::endl;  
  47.     std::cout<<“sp1 count:”<<sp1.use_count()<<std::endl;  
  48.     std::cout<<“sp2 count:”<<sp2.use_count()<<std::endl;  
  49.     std::cout<<“sp3 count:”<<sp3.use_count()<<std::endl;  
  50.   
  51.     return 0;  
  52. }  


輸出

 


(8)shared_ptr 在 STL 容器中的應用

由前面提到,shared_ptr 相比於 auto_ptr,可複製和賦值,故可用於 STL 容器中。
下面的例子9:將shared_ptr<int> 放入容器中,並對每個容器中的元素進行操作,如使shared_ptr 指向的int 變量 變為原來的2倍。
  1. #include <iostream>  
  2. #include <memory>  
  3. #include <vector>  
  4. #include <algorithm>  
  5. std::shared_ptr<int> double_it(const std::shared_ptr<int>& sp)  
  6. {  
  7.     *sp *= 2;  
  8.     return sp;  
  9. }  
  10. int main()  
  11. {  
  12.     std::vector<std::shared_ptr<int>> numbers;  
  13.   
  14.     numbers.push_back(std::shared_ptr<int>(new int(1)));  
  15.     numbers.push_back(std::shared_ptr<int>(new int(2)));  
  16.     numbers.push_back(std::shared_ptr<int>(new int(3)));  
  17.   
  18.     std::cout<<“initially”<<std::endl;  
  19.     for(std::vector<std::shared_ptr<int>>::const_iterator it = numbers.begin(); it != numbers.end(); it++)  
  20.     {  
  21.         std::cout<<*(*it)<<“(count = “<<(*it).use_count()<<“)”<<std::endl;  
  22.     }  
  23.   
  24.     std::transform(numbers.begin(), numbers.end(), numbers.begin(), double_it);  
  25.   
  26.     std::cout<<“after transformation”<<std::endl;  
  27.     for(std::vector<std::shared_ptr<int>>::const_iterator it = numbers.begin(); it != numbers.end(); it++)  
  28.     {  
  29.         std::cout<<*(*it)<<“(count = “<<(*it).use_count()<<“)”<<std::endl;  
  30.     }  
  31.   
  32.     return 0;  
  33. }  


輸出

(9)shared_ptr 在類層次結構中的應用

如 D 是 B 的子類,則可用shared_ptr<B>類型的對象(基類指針)接收shared_ptr<D>類型的對象(派生類指針)。
例子10
  1. #include <iostream>  
  2. #include <memory>  
  3. #include <string>  
  4. #include <vector>  
  5.   
  6. class Item  
  7. {  
  8. private:  
  9.     std::string title_;  
  10. public:  
  11.     explicit Item(const std::string& title):title_(title){}  
  12.     virtual ~Item(){}  
  13.   
  14.     virtual std::string Description() const = 0;  
  15.     std::string getTitle()const {return title_;}  
  16. };  
  17. class Book: public Item  
  18. {  
  19. private:  
  20.     int pages_;  
  21. public:  
  22.     Book(const std::string& title, int pages):Item(title),pages_(pages){}  
  23.   
  24.     virtual std::string Description()const {return “Book: ” + getTitle();}  
  25.     int getPages()const {return pages_;}  
  26. };  
  27.   
  28. class DVD: public Item  
  29. {  
  30. private:  
  31.     int tracks_;  
  32. public:  
  33.     DVD(const std::string& title, int tracks):Item(title),tracks_(tracks){}  
  34.   
  35.     virtual std::string Description() const {return “DVD: ” + getTitle();}  
  36.     int getTracks()const {return tracks_;}  
  37. };  
  38. int main()  
  39. {  
  40.     std::vector<std::shared_ptr<Item>> items;  
  41.     items.push_back(std::shared_ptr<Book>(new Book(“C++ Primer”,745)));  
  42.     items.push_back(std::shared_ptr<DVD>(new DVD(“MrVanGogh”,9)));  
  43.   
  44.     for(std::vector<std::shared_ptr<Item>>::const_iterator it = items.begin(); it != items.end(); it++)  
  45.     {  
  46.         std::cout<<(*it)->Description()<<std::endl;  
  47.     }  
  48.   
  49.     return 0;  
  50. }  


輸出


(10)cast 操作符

C++ 中提供了四種強制類型轉換操作符static_cast, dynamic_cast, const_cast, reinterpret_cast。而關於shared_ptr 無法利用這些原始的操作符進行轉換,其定義了自己的類型轉換操作符:static_pointer_cast, dynamic_pointer_cast, const_pointer_cast 。
如【9】中提到的 “若 D 是 B的子類 ”,其為向上轉換,但能否向下轉換呢?即從 shared_ptr<B> 到 shared_ptr<D> (當然,前提是:shared_ptr<B> 已指向了一個D對象,現在要做的就是“還原它”)。

I、使用 std::dynamic_pointer_cast,可以達到目的:
  1. template<class D, class B>  
  2. shared_ptr<D> dynamic_pointer_cast(const shared_ptr<B>& r);  


該函數不會拋出任何異常(noexcept)。若執行成功(前提:shared_ptr<B>對象 r 已經指向了一個D對象),則返回 shared_ptr<D> 共享資源的所有權,否則返回一個空對象。

例子11
  1. #include <iostream>  
  2. #include <memory>  
  3. #include <string>  
  4. class Item  
  5. {  
  6. private:  
  7.     std::string title_;  
  8. public:  
  9.     explicit Item(const std::string& title):title_(title){}  
  10.     virtual ~Item(){}  
  11.   
  12.     virtual std::string Description() const = 0;  
  13.     std::string getTitle()const {return title_;}  
  14. };  
  15. class Book: public Item  
  16. {  
  17. private:  
  18.     int pages_;  
  19. public:  
  20.     Book(const std::string& title, int pages):Item(title),pages_(pages){}  
  21.   
  22.     virtual std::string Description()const {return “Book: ” + getTitle();}  
  23.     int getPages()const {return pages_;}  
  24. };  
  25.   
  26. class DVD: public Item  
  27. {  
  28. private:  
  29.     int tracks_;  
  30. public:  
  31.     DVD(const std::string& title, int tracks):Item(title),tracks_(tracks){}  
  32.   
  33.     virtual std::string Description() const {return “DVD: ” + getTitle();}  
  34.     int getTracks()const {return tracks_;}  
  35. };  
  36. int main()  
  37. {  
  38.     std::shared_ptr<Item> spi(new DVD(“MrVanGogh”, 9));  
  39.     std::cout<<“spi counter: “<<spi.use_count()<<std::endl;  
  40.   
  41.     std::shared_ptr<Book> spb = std::dynamic_pointer_cast<Book>(spi);  
  42.     if(spb)  
  43.     {  
  44.         std::cout<<spb->getTitle()<<“, “<<spb->getPages()<<std::endl;  
  45.     }  
  46.     else  
  47.     {  
  48.         std::cout<<“pointer in spb is NULL”<<std::endl;  
  49.     }  
  50.   
  51.     std::shared_ptr<DVD> spd = std::dynamic_pointer_cast<DVD>(spi);  
  52.     if(spd)  
  53.     {  
  54.        std::cout<<spd->getTitle()<<“, “<<spd->getTracks()<<std::endl;  
  55.     }  
  56.     else  
  57.     {  
  58.        std::cout<<“pointer in spd is NULL”<<std::endl;  
  59.     }  
  60.   
  61.     std::cout<<“spi counter: “<<spi.use_count()<<std::endl;  
  62.     std::cout<<“spb counter: “<<spb.use_count()<<std::endl;  
  63.     std::cout<<“spd counter: “<<spd.use_count()<<std::endl;  
  64.   
  65.   
  66.     return 0;  
  67. }  


輸出


II、static_pointer_cast
根據 static_cast 的知識:編譯器隱式執行的任何類型轉換都可以由static_cast 顯示完成(如 int -> char;); 如果編譯器不提供自動轉換,使用 static_cast 來執行類型轉換也是很有用的(如,找回存放在 void* 指針中的值)。
注意:static_cast 轉換的一個特點就是:它只會生成原變量的副本,不會對原變量有任何修改。
而static_pointer_cast 工作的前提是:static_cast<T*>(r.get()) 必須是有效的。二者理念相同!
例子12
  1. #include <iostream>  
  2. #include <memory>  
  3. #include <vector>  
  4.   
  5. int main()  
  6. {  
  7.     std::vector<std::shared_ptr<void>> items;  
  8.   
  9.     std::shared_ptr<char> sp1(new char(‘A’));  
  10.     std::shared_ptr<int> sp2(new int(66)); //66 ASCII : ‘B’  
  11.   
  12.     std::cout<<“after creating the shared_ptr”<<std::endl;  
  13.     std::cout<<“sp1 counter: “<<sp1.use_count()<<std::endl;  
  14.     std::cout<<“sp2 counter: “<<sp2.use_count()<<std::endl;  
  15.   
  16.     items.push_back(sp1);  
  17.     items.push_back(sp2);  
  18.   
  19.     std::cout<<“after adding to the vector”<<std::endl;  
  20.     std::cout<<“sp1 counter: “<<sp1.use_count()<<std::endl;  
  21.     std::cout<<“sp2 counter: “<<sp2.use_count()<<std::endl;  
  22.   
  23.     std::shared_ptr<char> spc1 = std::static_pointer_cast<char>(*(items.begin()));  
  24.     if(spc1)  
  25.     {  
  26.         std::cout<<“&spc1: “<<&spc1<<std::endl;  
  27.         std::cout<<“*spc1: “<<*spc1<<std::endl;  
  28.     }  
  29.   
  30.     std::shared_ptr<char> spc2 = std::static_pointer_cast<char>(*(items.begin()+1));  
  31.     if(spc2)  
  32.     {  
  33.         std::cout<<“&spc2: “<<&spc2<<std::endl;  
  34.         std::cout<<“*spc2: “<<*spc2<<std::endl;  
  35.     }  
  36.     std::shared_ptr<short> spd2 = std::static_pointer_cast<short>(*(items.begin()+1));  
  37.     if(spd2)  
  38.     {  
  39.         std::cout<<“&spd2: “<<&spd2<<std::endl;  
  40.         std::cout<<“*spd2: “<<*spd2<<std::endl;  
  41.     }  
  42.     std::cout<<“after casting”<<std::endl;  
  43.     std::cout<<“sp1 couner: “<<sp1.use_count()<<std::endl;  
  44.     std::cout<<“spc1 couner: “<<spc1.use_count()<<std::endl;  
  45.     std::cout<<“sp2 couner: “<<sp2.use_count()<<std::endl;  
  46.     std::cout<<“spc2 couner: “<<spc2.use_count()<<std::endl;  
  47.     std::cout<<“spd2 couner: “<<spd2.use_count()<<std::endl;  
  48.   
  49.     return 0;  
  50. }  


輸出


III、const_pointer_cast
若 const_cast<T*>(sp.get()) 返回一個NULL指針,則 std::cosnt_pointer_cast 返回一個空的對象。否則,它返回一個shared_ptr<T>對象。
原型:
  1. template<classT,class U>  
  2. shared_ptr<T>cosnt_pointer_cast(const shared_ptr<U>& r);  


四、智能指針:std::tr1::weak_ptr


引入:由於 shared_ptr 智能指針的缺陷:無法檢測循環引用(關於 share_ptr 的循環引用詳細內容,可參見我的另一篇文章:Effective shared_ptr)—這是所有引用型智能指針的硬傷。為瞭解決這個問題又引入了 weak_ptr 指針。
概念:該類型智能指針也是指向由 shared_ptr 所指向的資源,但是不增加引用計數,故稱為”弱引用(weak reference)“ 。當最後擁有資源的最後一個 shared_ptr 對象離開其作用域時,資源被釋放,weak_ptr 被標記為無效狀態。並且可以通過函數 expired() 來檢查是是否 weak_ptr 處於無效狀態。weak_ptr 在訪問所引用的對象前必須先轉換為 shared_ptr, 即其【來於 shared_ptr 也去於 shared_ptr】。
作用(觀察者的角度):weak_ptr 是用來表達臨時所有權的概念:當某個對象只有存在時才需要被訪問,而且隨時可以被他人刪除時,可以使用 weak_ptr 來跟蹤該對象。需要獲得臨時所有權時,則將其轉換為 shared_ptr ,此時若原來的 shared_ptr 被銷毀,則該對象的生命週期將延長至這個臨時生成的 shared_ptr 同樣被銷毀為止。
線程安全:考慮到多線程環境下,可通過std::weak_ptr::lock函數創建一個新的shared_ptr 管理對象的共享所有權—–作為臨時訪問的shared_ptr(此時引用計數是會增1 的,即此臨時的 shared_ptr 若沒有離開其作用域,共享的資源是不會被釋放的)。如果沒有管理的對象,即*this 為空,則返回的 shared_ptr 也是空;否則返回:shared_ptr<T>(*this) 。
例子13
  1. #include <iostream>  
  2. #include <memory>  
  3.   
  4. void show(const std::weak_ptr<int>& wp)  
  5. {  
  6.     std::shared_ptr<int> sp = wp.lock();  
  7.     std::cout<<*sp<<std::endl;  
  8. }  
  9. int main()  
  10. {  
  11.     std::weak_ptr<int> wp;  
  12.   
  13.     { //create a namesapce deliberately  
  14.         std::shared_ptr<int> sp(new int(10));  
  15.         wp = sp;  
  16.   
  17.         show(wp);  
  18.     }  
  19.   
  20.     std::cout<<“expire: “<<std::boolalpha<<wp.expired()<<std::endl;  
  21.   
  22.     return 0;  
  23. }  


輸出

由於shared_ptr智能指針存在缺陷,故用好它也是很關鍵的問題,具體內容續集:Effective shared_ptr
未經允許不得轉載:GoMCU » C++ 智能指針類 auto_ptr shared_ptr weak_ptr