程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++智能指針實例詳解

C++智能指針實例詳解

編輯:關於C++

C++智能指針實例詳解。本站提示廣大學習愛好者:(C++智能指針實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++智能指針實例詳解正文


本文經由過程實例具體論述了C++關於智能指針的概念及用法,有助於讀者加深對智能指針的懂得。概況以下:

1、簡介

因為 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)。
 
2、詳細應用

1、總括

關於編譯器來講,智能指針現實上是一個棧對象,並不是指針類型,在棧對象性命期行將停止時,智能指針經由過程析構函數釋放有它治理的堆內存。一切智能指針都重載了“operator->”操作符,直接前往對象的援用,用以操尴尬刁難象。拜訪智能指針本來的辦法則應用“.”操作符。

拜訪智能指針包括的裸指針則可以用 get() 函數。因為智能指針是一個對象,所以if (my_smart_object)永久為真,要斷定智能指針的裸指針能否為空,須要如許斷定:if (my_smart_object.get())。

智能指針包括了 reset() 辦法,假如不傳遞參數(或許傳遞 NULL),則智能指針會釋放以後治理的內存。假如傳遞一個對象,則智能指針會釋放以後對象,來治理新傳入的對象。
我們編寫一個測試類來幫助剖析:

class Simple {
 public:
 Simple(int param = 0) {
  number = param;
  std::cout << "Simple: " << number << std::endl; 
 }
 ~Simple() {
  std::cout << "~Simple: " << number << std::endl;
 }
 void PrintSomething() {
  std::cout << "PrintSomething: " << info_extend.c_str() << std::endl;
 }
 std::string info_extend;
 int number;
};

2、std::auto_ptr

std::auto_ptr 屬於 STL,固然在 namespace std 中,包括頭文件 #include<memory> 即可以應用。std::auto_ptr 可以或許便利的治理單個堆內存對象。

我們從代碼開端剖析:

void TestAutoPtr() {
std::auto_ptr<Simple> my_memory(new Simple(1));  // 創立對象,輸入:Simple:1
if (my_memory.get()) {              // 斷定智能指針能否為空
my_memory->PrintSomething();          // 應用 operator-> 挪用智能指針對象中的函數
my_memory.get()->info_extend = "Addition";   // 應用 get() 前往裸指針,然後給外部對象賦值
my_memory->PrintSomething();          // 再次打印,注解上述賦值勝利
(*my_memory).info_extend += " other";      // 應用 operator* 前往智能指針外部對象,然後用“.”挪用智能指針對象中的函數
my_memory->PrintSomething();          // 再次打印,注解上述賦值勝利
 }
}                       //my_memory棧對象行將停止性命期,析構堆對象Simple(1)

履行成果為:

Simple: 1
PrintSomething:
PrintSomething: Addition
PrintSomething: Addition other
~Simple: 1

上述為正常應用 std::auto_ptr 的代碼,一切仿佛都優越,不管若何不消我們顯示應用活該的 delete 了。
 
其實好景不長,我們看看以下的另外一個例子:

void TestAutoPtr2() {
 std::auto_ptr<Simple> my_memory(new Simple(1));
 if (my_memory.get()) {
  std::auto_ptr<Simple> my_memory2;  // 創立一個新的 my_memory2 對象
  my_memory2 = my_memory;       // 復制舊的 my_memory 給 my_memory2
  my_memory2->PrintSomething();    // 輸入信息,復制勝利
  my_memory->PrintSomething();    // 瓦解
 }
}

終究如上代碼招致瓦解,如上代碼時相對相符 C++ 編程思惟的,竟然瓦解了,跟進 std::auto_ptr 的源碼後,我們看到,禍首罪魁是“my_memory2 = my_memory”,這行代碼,my_memory2 完整牟取了 my_memory 的內存治理一切權,招致 my_memory 懸空,最初應用時招致瓦解。

所以,應用 std::auto_ptr 時,相對不克不及應用“operator=”操作符。作為一個庫,不許可用戶應用,確沒有明白謝絕,若干會認為有點出乎預感。
 
看完 std::auto_ptr 好景不長的第一個例子後,讓我們再來看一個:

void TestAutoPtr3() {
 std::auto_ptr<Simple> my_memory(new Simple(1));
 
 if (my_memory.get()) {
  my_memory.release();
 }
}

履行成果為:

Simple: 1

看到甚麼異常了嗎?我們創立出來的對象沒有被析構,沒有輸入“~Simple: 1”,招致內存洩漏。當我們不想讓 my_memory 持續生計下去,我們挪用 release() 函數釋放內存,成果卻招致內存洩漏(在內存受限體系中,假如my_memory占用太多內存,我們會斟酌在應用完成後,連忙清償,而不是比及 my_memory 停止性命期後才清償)。

准確的代碼應當為:

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

void TestAutoPtr3() {
 std::auto_ptr<Simple> my_memory(new Simple(1));
 if (my_memory.get()) {
  my_memory.reset(); // 釋放 my_memory 外部治理的內存
 }
}

本來 std::auto_ptr 的 release() 函數只是讓出內存一切權,這明顯也不相符 C++ 編程思惟。
總結:std::auto_ptr 可用來治理單個對象的對內存,然則,請留意以下幾點:

(1)    盡可能不要應用“operator=”。假如應用了,請不要再應用先前對象。
(2)    記住 release() 函數不會釋放對象,僅僅清償一切權。
(3)    std::auto_ptr 最好不要當做參數傳遞(讀者可以自行寫代碼肯定為何不克不及)。
(4)    因為 std::auto_ptr 的“operator=”成績,有其治理的對象不克不及放入 std::vector 等容器中。
應用一個 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 末路人的幾個成績。
我們照樣從代碼開端剖析:

void TestScopedPtr() {
 boost::scoped_ptr<Simple> my_memory(new Simple(1));
 if (my_memory.get()) {
  my_memory->PrintSomething();
  my_memory.get()->info_extend = "Addition";
  my_memory->PrintSomething();
  (*my_memory).info_extend += " other";
  my_memory->PrintSomething();
  
  my_memory.release();      // 編譯 error: scoped_ptr 沒有 release 函數
  std::auto_ptr<Simple> my_memory2;
  my_memory2 = my_memory;    // 編譯 error: scoped_ptr 沒有重載 operator=,不會招致一切權轉移
 }
}

起首,我們可以看到,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 也是用於治理單個堆內存對象的。
我們照樣從代碼開端剖析:

void TestSharedPtr(boost::shared_ptr<Simple> memory) { // 留意:無需應用 reference (或 const reference)
 memory->PrintSomething();
 std::cout << "TestSharedPtr UseCount: " << memory.use_count() << std::endl;
}
 
void TestSharedPtr2() {
 boost::shared_ptr<Simple> my_memory(new Simple(1));
 if (my_memory.get()) {
  my_memory->PrintSomething();
  my_memory.get()->info_extend = "Addition";
  my_memory->PrintSomething();
  (*my_memory).info_extend += " other";
  my_memory->PrintSomething();
 }
 
 std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;
 TestSharedPtr(my_memory);
 std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;
 
 //my_memory.release();// 編譯 error: 異樣,shared_ptr 也沒有 release 函數
}

履行成果為:

Simple: 1
PrintSomething:
PrintSomething: Addition
PrintSomething: Addition other
TestSharedPtr2 UseCount: 1
PrintSomething: Addition other
TestSharedPtr UseCount: 2
TestSharedPtr2 UseCount: 1
~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 一樣,也是獨享一切權的。

我們照樣從代碼開端剖析:

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

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 一樣,外部應用了援用計數。

我們照樣從代碼開端剖析:

void TestSharedArray(boost::shared_array<Simple> memory) { // 留意:無需應用 reference (或 const reference)
 std::cout << "TestSharedArray UseCount: " << memory.use_count() << std::endl;
}
 
void TestSharedArray2() {
 boost::shared_array<Simple> my_memory(new Simple[2]);
 if (my_memory.get()) {
  my_memory[0].PrintSomething();
  my_memory.get()[0].info_extend = "Addition 00";
  my_memory[0].PrintSomething();
  my_memory[1].PrintSomething();
  my_memory.get()[1].info_extend = "Addition 11";
  my_memory[1].PrintSomething();
  //(*my_memory)[0].info_extend += " other"; // 編譯 error,scoped_ptr 沒有重載 operator*
 }
 std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;
 TestSharedArray(my_memory);
 std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;
}

履行成果為:

Simple: 0
Simple: 0
PrintSomething:
PrintSomething: Addition 00
PrintSomething:
PrintSomething: Addition 11
TestSharedArray2 UseCount: 1
TestSharedArray UseCount: 2
TestSharedArray2 UseCount: 1
~Simple: 0
~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 也響應掉效。
我們照樣從代碼開端剖析:

  void TestWeakPtr() {
   boost::weak_ptr<Simple> my_memory_weak;
   boost::shared_ptr<Simple> my_memory(new Simple(1));
 
   std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;
   my_memory_weak = my_memory;
   std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;
}

    履行成果為:

Simple: 1
TestWeakPtr boost::shared_ptr UseCount: 1
TestWeakPtr boost::shared_ptr UseCount: 1
~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汗)。小我感到這個智能指針沒太年夜用途,至多我沒用過。有興致的同伙本身研討一下源代碼哦。
 
 
3、總結

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

1、在可使用 boost 庫的場所下,謝絕應用 std::auto_ptr,由於其不只不相符 C++ 編程思惟,並且極輕易失足。
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 函數),由於可以用智能指針去治理。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved