C++智能指針


C++智能指針

C++ 11 新特性 智能指針(shared_ptr, unique_ptr, weak_ptr)

shared_ptr

shared_ptr基本用法

shared_ptr采用引用計數的方式管理所指向的對象。當有一個新的shared_ptr指向同一個對象時(復制shared_ptr等),引用計數加1。當shared_ptr離開作用域時,引用計數減1。當引用計數為0時,釋放所管理的內存。

這樣做的好處在於解放了程序員手動釋放內存的壓力。之前,為了處理程序中的異常情況,往往需要將指針手動封裝到類中,通過析構函數來釋放動態分配的內存;現在這一過程就可以交給shared_ptr去做了。

一般我們使用make_shared來獲得shared_ptr。

 1 cout<<"test shared_ptr base usage:"<<endl;
 2 shared_ptr<string> p1 = make_shared<string>("");
 3 if(p1 && p1->empty())
 4     *p1 = "hello";
 5 
 6 auto p2 = make_shared<string>("world");
 7 cout<<*p1<<' '<<*p2<<endl;
 8 
 9 cout<<"test shared_ptr use_count:"<<endl;
10 cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<endl;
11 
12 auto p3 = p2;
13 cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;
14 p2 = p1;
15 cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;

 

shared_ptr和new

shared_ptr可以使用一個new表達式返回的指針進行初始化。

1 cout<<"test shared_ptr and new:"<<endl;
2 shared_ptr<int> p4(new int(1024));
3 //shared_ptr<int> p5 = new int(1024); // wrong, no implicit constructor
4 cout<<*p4<<endl;

 

但是,不能將一個new表達式返回的指針賦值給shared_ptr。

另外,特別需要注意的是,不要混用new和shared_ptr!

 1 void process(shared_ptr<int> ptr)
 2 {
 3     cout<<"in process use_count:"<<ptr.use_count()<<endl;
 4 }
 5 
 6 cout<<"don't mix shared_ptr and normal pointer:"<<endl;
 7 shared_ptr<int> p5(new int(1024));
 8 process(p5);
 9 int v5 = *p5;
10 cout<<"v5: "<<v5<<endl;
11 
12 int *p6 = new int(1024);
13 process(shared_ptr<int>(p6));
14 int v6 = *p6;
15 cout<<"v6: "<<v6<<endl;

 

上面的程序片段會輸出:

1 in process use_count:2
2 v5: 1024
3 in process use_count:1
4 v6: 0

 

可以看到,第二次process p6時,shared_ptr的引用計數為1,當離開process的作用域時,會釋放對應的內存,此時p6成為了懸掛指針。

所以,一旦將一個new表達式返回的指針交由shared_ptr管理之后,就不要再通過普通指針訪問這塊內存!

shared_ptr.reset

shared_ptr可以通過reset方法重置指向另一個對象,此時原對象的引用計數減一。

1 cout<<"test shared_ptr reset:"<<endl;
2 cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 nt:"<<p3.use_count()<<endl;
3 p1.reset(new string("cpp11"));
4 cout<<"p1 cnt:"<<p1.use_count()<<"\tp2 cnt:"<<p2.use_count()<<"\tp3 cnt:"<<p3.use_count()<<endl;

 

shared_ptr deleter

可以定制一個deleter函數,用於在shared_ptr釋放對象時調用。

 1 void print_at_delete(int *p)
 2 {
 3     cout<<"deleting..."<<p<<'\t'<<*p<<endl;
 4     delete p;
 5 }
 6 
 7 cout<<"test shared_ptr deleter:"<<endl;
 8 int *p7 = new int(1024);
 9 shared_ptr<int> p8(p7, print_at_delete);
10 p8 = make_shared<int>(1025);

 

unique_ptr

unique_ptr基本用法

unique_ptr對於所指向的對象,正如其名字所示,是獨占的。所以,不可以對unique_ptr進行拷貝、賦值等操作,但是可以通過release函數在unique_ptr之間轉移控制權。

 1 cout<<"test unique_ptr base usage:"<<endl;
 2 unique_ptr<int> up1(new int(1024));
 3 cout<<"up1: "<<*up1<<endl;
 4 unique_ptr<int> up2(up1.release());
 5 cout<<"up2: "<<*up2<<endl;
 6 //unique_ptr<int> up3(up1); // wrong, unique_ptr can not copy
 7 //up2 = up1; // wrong, unique_ptr can not copy
 8 unique_ptr<int> up4(new int(1025));
 9 up4.reset(up2.release());
10 cout<<"up4: "<<*up4<<endl;
11 unique_ptr作為參數和返

 

回值

上述對於拷貝的限制,有兩個特殊情況,即unique_ptr可以作為函數的返回值和參數使用,這時雖然也有隱含的拷貝存在,但是並非不可行的。

 1 unique_ptr<int> clone(int p)
 2 {
 3     return unique_ptr<int>(new int(p));
 4 }
 5 
 6 void process_unique_ptr(unique_ptr<int> up)
 7 {
 8     cout<<"process unique ptr: "<<*up<<endl;
 9 }
10 
11 cout<<"test unique_ptr parameter and return value:"<<endl;
12 auto up5 = clone(1024);
13 cout<<"up5: "<<*up5<<endl;
14 process_unique_ptr(move(up5));
15 //cout<<"up5 after process: "<<*up5<<endl; // would cause segmentfault

 

這里的std::move函數,以后再單獨具體細說^_^

unique_ptr deleter

unique_ptr同樣可以設置deleter,和shared_ptr不同的是,它需要在模板參數中指定deleter的類型。好在我們有decltype這個利器,不然寫起來好麻煩。

1 cout<<"test unique_ptr deleter:"<<endl;
2 int *p9 = new int(1024);
3 unique_ptr<int, decltype(print_at_delete) *> up6(p9, print_at_delete);
4 unique_ptr<int> up7(new int(1025));
5 up6.reset(up7.release());

 

weak_ptr

weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的對象,但是卻不增加對象的引用計數。這樣就有可能出現weak_ptr所指向的對象實際上已經被釋放了的情況。因此,weak_ptr有一個lock函數,嘗試取回一個指向對象的shared_ptr。

1 cout<<"test weak_ptr basic usage:"<<endl;
2 auto p10 = make_shared<int>(1024);
3 weak_ptr<int> wp1(p10);
4 cout<<"p10 use_count: "<<p10.use_count()<<endl;
5 //p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
6 shared_ptr<int> p11 = wp1.lock();
7 if(p11) cout<<"wp1: "<<*p11<<" use count: "<<p11.use_count()<<endl;

 

總結

  • shared_ptr采用引用計數的方式管理所指向的對象。
  • shared_ptr可以使用一個new表達式返回的指針進行初始化;但是,不能將一個new表達式返回的指針賦值給shared_ptr。
  • 一旦將一個new表達式返回的指針交由shared_ptr管理之后,就不要再通過普通指針訪問這塊內存。
  • shared_ptr可以通過reset方法重置指向另一個對象,此時原對象的引用計數減一。
  • 可以定制一個deleter函數,用於在shared_ptr釋放對象時調用。
  • unique_ptr對於所指向的對象,是獨占的。
  • 不可以對unique_ptr進行拷貝、賦值等操作,但是可以通過release函數在unique_ptr之間轉移控制權。
  • unique_ptr可以作為函數的返回值和參數使用。
  • unique_ptr同樣可以設置deleter,需要在模板參數中指定deleter的類型。
  • weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的對象,但是卻不增加對象的引用計數。
  • weak_ptr有一個lock函數,嘗試取回一個指向對象的shared_ptr。
  • 完整代碼詳見smart_pointer.cpp

 

BOOST 智能指針

一、簡介

由於 C++ 語言沒有自動內存回收機制,程序員每次 new 出來的內存都要手動 delete。程序員忘記 delete,流程太復雜,最終導致沒有 delete,異常導致程序過早退出,沒有執行 delete 的情況並不罕見。

用智能指針便可以有效緩解這類問題,本文主要講解參見的智能指針的用法。包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr你可能會想,如此多的智能指針就為了解決new、delete匹配問題,真的有必要嗎?看完這篇文章后,我想你心里自然會有答案。

下面就按照順序講解如上 7 種智能指針(smart_ptr)。

二、具體使用

1、總括

對於編譯器來說,智能指針實際上是一個棧對象,並非指針類型,在棧對象生命期即將結束時,智能指針通過析構函數釋放有它管理的堆內存。所有智能指針都重載了“operator->”操作符,直接返回對象的引用,用以操作對象。訪問智能指針原來的方法則使用“.”操作符。

訪問智能指針包含的裸指針則可以用 get() 函數。由於智能指針是一個對象,所以if (my_smart_object)永遠為真,要判斷智能指針的裸指針是否為空,需要這樣判斷:if (my_smart_object.get())。

智能指針包含了 reset() 方法,如果不傳遞參數(或者傳遞 NULL),則智能指針會釋放當前管理的內存。如果傳遞一個對象,則智能指針會釋放當前對象,來管理新傳入的對象。

我們編寫一個測試類來輔助分析:

 1 class Simple {
 2  public:
 3   Simple(int param = 0) {
 4     number = param;
 5     std::cout << "Simple: " << number << std::endl; 
 6   }
 7 
 8   ~Simple() {
 9     std::cout << "~Simple: " << number << std::endl;
10   }
11 
12   void PrintSomething() {
13     std::cout << "PrintSomething: " << info_extend.c_str() << std::endl;
14   }
15 
16   std::string info_extend;
17   int number;
18 };

 

2、std::auto_ptr

std::auto_ptr 屬於 STL,當然在 namespace std 中,包含頭文件 #include 便可以使用。std::auto_ptr 能夠方便的管理單個堆內存對象。

我們從代碼開始分析:

 1 void TestAutoPtr() {
 2 std::auto_ptr<Simple> my_memory(new Simple(1));   // 創建對象,輸出:Simple:1
 3 if (my_memory.get()) {                            // 判斷智能指針是否為空
 4 my_memory->PrintSomething();                    // 使用 operator-> 調用智能指針對象中的函數
 5 my_memory.get()->info_extend = "Addition";      // 使用 get() 返回裸指針,然后給內部對象賦值
 6 my_memory->PrintSomething();                    // 再次打印,表明上述賦值成功
 7 (*my_memory).info_extend += " other";           // 使用 operator* 返回智能指針內部對象,然后用“.”調用智能指針對象中的函數
 8 my_memory->PrintSomething();                    // 再次打印,表明上述賦值成功
 9   }
10 }   

 

 // my_memory 棧對象即將結束生命期,析構堆對象 Simple(1)

執行結果為:

1 Simple: 1
2 PrintSomething:
3 PrintSomething: Addition
4 PrintSomething: Addition other
5 ~Simple: 1

 

上述為正常使用 std::auto_ptr 的代碼,一切似乎都良好,無論如何不用我們顯示使用該死的delete 了。

其實好景不長,我們看看如下的另一個例子:

1 void TestAutoPtr2() {
2   std::auto_ptr<Simple> my_memory(new Simple(1));
3   if (my_memory.get()) {
4     std::auto_ptr<Simple> my_memory2;   // 創建一個新的 my_memory2 對象
5     my_memory2 = my_memory;             // 復制舊的 my_memory 給 my_memory2
6     my_memory2->PrintSomething();       // 輸出信息,復制成功
7     my_memory->PrintSomething();        // 崩潰
8   }
9 }

 

最終如上代碼導致崩潰,如上代碼時絕對符合 C++ 編程思想的,居然崩潰了,跟進 std::auto_ptr 的源碼后,我們看到,罪魁禍首是“my_memory2 = my_memory”,這行代碼,my_memory2 完全奪取了 my_memory 的內存管理所有權,導致 my_memory 懸空,最后使用時導致崩潰。

所以,使用 std::auto_ptr 時,絕對不能使用“operator=”操作符。作為一個庫,不允許用戶使用,確沒有明確拒絕[1],多少會覺得有點出乎預料。

看完 std::auto_ptr 好景不長的第一個例子后,讓我們再來看一個:

1 void TestAutoPtr3() {
2   std::auto_ptr<Simple> my_memory(new Simple(1));
3 
4   if (my_memory.get()) {
5     my_memory.release();
6   }
7 }

 

執行結果為:

1 Simple: 1

 

看到什么異常了嗎?我們創建出來的對象沒有被析構,沒有輸出“~Simple: 1”,導致內存泄露。當我們不想讓 my_memory 繼續生存下去,我們調用 release() 函數釋放內存,結果卻導致內存泄露(在內存受限系統中,如果my_memory占用太多內存,我們會考慮在使用完成后,立刻歸還,而不是等到 my_memory 結束生命期后才歸還)。

正確的代碼應該為:

1 void TestAutoPtr3() {
2   std::auto_ptr<Simple> my_memory(new Simple(1));
3   if (my_memory.get()) {
4     Simple* temp_memory = my_memory.release();
5     delete temp_memory;
6   }
7 }

 

1 void TestAutoPtr3() {
2   std::auto_ptr<Simple> my_memory(new Simple(1));
3   if (my_memory.get()) {
4     my_memory.reset();  // 釋放 my_memory 內部管理的內存
5   }
6 }

 

原來 std::auto_ptr 的 release() 函數只是讓出內存所有權,這顯然也不符合 C++ 編程思想。

總結:std::auto_ptr 可用來管理單個對象的對內存,但是,請注意如下幾點:

(1)    盡量不要使用“operator=”。如果使用了,請不要再使用先前對象。

(2)    記住 release() 函數不會釋放對象,僅僅歸還所有權。

(3)    std::auto_ptr 最好不要當成參數傳遞(讀者可以自行寫代碼確定為什么不能)。

(4)    由於 std::auto_ptr 的“operator=”問題,有其管理的對象不能放入 std::vector等容器中。

(5)    ……

使用一個 std::auto_ptr 的限制還真多,還不能用來管理堆內存數組,這應該是你目前在想的事情吧,我也覺得限制挺多的,哪天一個不小心,就導致問題了。

由於 std::auto_ptr 引發了諸多問題,一些設計並不是非常符合 C++ 編程思想,所以引發了下面 boost 的智能指針,boost 智能指針可以解決如上問題。

讓我們繼續向下看。

3、boost::scoped_ptr

boost::scoped_ptr 屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。boost::scoped_ptr 跟 std::auto_ptr 一樣,可以方便的管理單個堆內存對象,特別的是,boost::scoped_ptr 獨享所有權,避免了 std::auto_ptr 惱人的幾個問題。

我們還是從代碼開始分析:

 1 void TestScopedPtr() {
 2   boost::scoped_ptr<Simple> my_memory(new Simple(1));
 3   if (my_memory.get()) {
 4     my_memory->PrintSomething();
 5     my_memory.get()->info_extend = "Addition";
 6     my_memory->PrintSomething();
 7     (*my_memory).info_extend += " other";
 8     my_memory->PrintSomething();
 9 
10     my_memory.release();           // 編譯 error: scoped_ptr 沒有 release 函數
11     std::auto_ptr<Simple> my_memory2;
12     my_memory2 = my_memory;        // 編譯 error: scoped_ptr 沒有重載 operator=,不會導致所有權轉移
13   }
14 }

 

首先,我們可以看到,boost::scoped_ptr 也可以像 auto_ptr 一樣正常使用。但其沒有 release() 函數,不會導致先前的內存泄露問題。其次,由於 boost::scoped_ptr 是獨享所有權的,所以明確拒絕用戶寫“my_memory2 = my_memory”之類的語句,可以緩解 std::auto_ptr 幾個惱人的問題。

由於 boost::scoped_ptr 獨享所有權,當我們真真需要復制智能指針時,需求便滿足不了了,如此我們再引入一個智能指針,專門用於處理復制,參數傳遞的情況,這便是如下的 boost::shared_ptr。

4、boost::shared_ptr

boost::shared_ptr 屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。在上面我們看到 boost::scoped_ptr 獨享所有權,不允許賦值、拷貝,boost::shared_ptr 是專門用於共享所有權的,由於要共享所有權,其在內部使用了引用計數。boost::shared_ptr 也是用於管理單個堆內存對象的。

我們還是從代碼開始分析:

 1 void TestSharedPtr(boost::shared_ptr<Simple> memory) {  // 注意:無需使用 reference (或 const reference)
 2   memory->PrintSomething();
 3   std::cout << "TestSharedPtr UseCount: " << memory.use_count() << std::endl;
 4 }
 5 
 6 void TestSharedPtr2() {
 7   boost::shared_ptr<Simple> my_memory(new Simple(1));
 8   if (my_memory.get()) {
 9     my_memory->PrintSomething();
10     my_memory.get()->info_extend = "Addition";
11     my_memory->PrintSomething();
12     (*my_memory).info_extend += " other";
13     my_memory->PrintSomething();
14   }
15 
16   std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;
17   TestSharedPtr(my_memory);
18   std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;
19 
20   //my_memory.release();// 編譯 error: 同樣,shared_ptr 也沒有 release 函數
21 }

 

執行結果為:

1 Simple: 1
2 PrintSomething:
3 PrintSomething: Addition
4 PrintSomething: Addition other
5 TestSharedPtr2 UseCount: 1
6 PrintSomething: Addition other
7 TestSharedPtr UseCount: 2
8 TestSharedPtr2 UseCount: 1
9 ~Simple: 1

 

boost::shared_ptr 也可以很方便的使用。並且沒有 release() 函數。關鍵的一點,boost::shared_ptr 內部維護了一個引用計數,由此可以支持復制、參數傳遞等。boost::shared_ptr提供了一個函數 use_count() ,此函數返回 boost::shared_ptr 內部的引用計數。查看執行結果,我們可以看到在 TestSharedPtr2 函數中,引用計數為 1,傳遞參數后(此處進行了一次復制),在函數TestSharedPtr 內部,引用計數為2,在 TestSharedPtr 返回后,引用計數又降低為 1。當我們需要使用一個共享對象的時候,boost::shared_ptr 是再好不過的了。

在此,我們已經看完單個對象的智能指針管理,關於智能指針管理數組,我們接下來講到。

5、boost::scoped_array

boost::scoped_array 屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。

boost::scoped_array 便是用於管理動態數組的。跟 boost::scoped_ptr 一樣,也是獨享所有權的。

我們還是從代碼開始分析:

 1 void TestScopedArray() {
 2       boost::scoped_array<Simple> my_memory(new Simple[2]); // 使用內存數組來初始化
 3       if (my_memory.get()) {
 4         my_memory[0].PrintSomething();
 5         my_memory.get()[0].info_extend = "Addition";
 6         my_memory[0].PrintSomething();
 7         (*my_memory)[0].info_extend += " other";            // 編譯 error,scoped_ptr 沒有重載 operator*
 8         my_memory[0].release();                             // 同上,沒有 release 函數
 9         boost::scoped_array<Simple> my_memory2;
10         my_memory2 = my_memory;                             // 編譯 error,同上,沒有重載 operator=
11       }
12     }

 

boost::scoped_array 的使用跟 boost::scoped_ptr 差不多,不支持復制,並且初始化的時候需要使用動態數組。另外,boost::scoped_array 沒有重載“operator*”,其實這並無大礙,一般情況下,我們使用 get() 函數更明確些。

下面肯定應該講 boost::shared_array 了,一個用引用計數解決復制、參數傳遞的智能指針類。

6、boost::shared_array

boost::shared_array 屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。

由於 boost::scoped_array 獨享所有權,顯然在很多情況下(參數傳遞、對象賦值等)不滿足需求,由此我們引入 boost::shared_array。跟 boost::shared_ptr 一樣,內部使用了引用計數。

我們還是從代碼開始分析:

 1 void TestSharedArray(boost::shared_array<Simple> memory) {  // 注意:無需使用 reference (或 const reference)
 2   std::cout << "TestSharedArray UseCount: " << memory.use_count() << std::endl;
 3 }
 4 
 5 void TestSharedArray2() {
 6   boost::shared_array<Simple> my_memory(new Simple[2]);
 7   if (my_memory.get()) {
 8     my_memory[0].PrintSomething();
 9     my_memory.get()[0].info_extend = "Addition 00";
10     my_memory[0].PrintSomething();
11     my_memory[1].PrintSomething();
12     my_memory.get()[1].info_extend = "Addition 11";
13     my_memory[1].PrintSomething();
14     //(*my_memory)[0].info_extend += " other";  // 編譯 error,scoped_ptr 沒有重載 operator*
15   }
16   std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;
17   TestSharedArray(my_memory);
18   std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;
19 }

 

執行結果為:

 1 Simple: 0
 2 Simple: 0
 3 PrintSomething:
 4 PrintSomething: Addition 00
 5 PrintSomething:
 6 PrintSomething: Addition 11
 7 TestSharedArray2 UseCount: 1
 8 TestSharedArray UseCount: 2
 9 TestSharedArray2 UseCount: 1
10 ~Simple: 0
11 ~Simple: 0

 

跟 boost::shared_ptr 一樣,使用了引用計數,可以復制,通過參數來傳遞。

至此,我們講過的智能指針有 std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array。這幾個智能指針已經基本夠我們使用了,90%的使用過標准智能指針的代碼就這 5 種。可如下還有兩種智能指針,它們肯定有用,但有什么用處呢,一起看看吧。

7、boost::weak_ptr

boost::weak_ptr 屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。

在講 boost::weak_ptr 之前,讓我們先回顧一下前面講解的內容。似乎 boost::scoped_ptr、boost::shared_ptr 這兩個智能指針就可以解決所有單個對象內存的管理了,這兒還多出一個 boost::weak_ptr,是否還有某些情況我們沒納入考慮呢?

回答:有。首先 boost::weak_ptr 是專門為 boost::shared_ptr 而准備的。有時候,我們只關心能否使用對象,並不關心內部的引用計數。boost::weak_ptr 是 boost::shared_ptr 的觀察者(Observer)對象,觀察者意味着 boost::weak_ptr 只對 boost::shared_ptr 進行引用,而不改變其引用計數,當被觀察的 boost::shared_ptr 失效后,相應的 boost::weak_ptr 也相應失效。

我們還是從代碼開始分析:

1 void TestWeakPtr() {
2       boost::weak_ptr<Simple> my_memory_weak;
3       boost::shared_ptr<Simple> my_memory(new Simple(1));
4 
5       std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;
6       my_memory_weak = my_memory;
7       std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;
8 }

 

執行結果為:

1 Simple: 1
2 TestWeakPtr boost::shared_ptr UseCount: 1
3 TestWeakPtr boost::shared_ptr UseCount: 1
4 ~Simple: 1

 

我們看到,盡管被賦值了,內部的引用計數並沒有什么變化,當然,讀者也可以試試傳遞參數等其他情況。

現在要說的問題是,boost::weak_ptr 到底有什么作用呢?從上面那個例子看來,似乎沒有任何作用,其實 boost::weak_ptr 主要用在軟件架構設計中,可以在基類(此處的基類並非抽象基類,而是指繼承於抽象基類的虛基類)中定義一個 boost::weak_ptr,用於指向子類的 boost::shared_ptr,這樣基類僅僅觀察自己的 boost::weak_ptr 是否為空就知道子類有沒對自己賦值了,而不用影響子類 boost::shared_ptr 的引用計數,用以降低復雜度,更好的管理對象。

8、boost::intrusive_ptr

boost::intrusive_ptr屬於 boost 庫,定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。

講完如上 6 種智能指針后,對於一般程序來說 C++ 堆內存管理就夠用了,現在有多了一種boost::intrusive_ptr,這是一種插入式的智能指針,內部不含有引用計數,需要程序員自己加入引用計數,不然編譯不過(⊙﹏⊙b汗)。個人感覺這個智能指針沒太大用處,至少我沒用過。有興趣的朋友自己研究一下源代碼哦J。

三、總結

如上講了這么多智能指針,有必要對這些智能指針做個總結:

1、在可以使用 boost 庫的場合下,拒絕使用 std::auto_ptr,因為其不僅不符合 C++ 編程思想,而且極容易出錯[2]。

2、在確定對象無需共享的情況下,使用 boost::scoped_ptr(當然動態數組使用 boost::scoped_array)。

3、在對象需要共享的情況下,使用 boost::shared_ptr(當然動態數組使用 boost::shared_array)。

4、在需要訪問 boost::shared_ptr 對象,而又不想改變其引用計數的情況下,使用 boost::weak_ptr,一般常用於軟件框架設計中。

5、最后一點,也是要求最苛刻一點:在你的代碼中,不要出現 delete 關鍵字(或 C 語言的free 函數),因為可以用智能指針去管理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM