C++智能指針

什麼是智能指針?

智能指針的原理:
將基本類型指針封裝爲類對象指針(這個類肯定是個模板,以適應不同基本類型的需求),並在析構函數裏編寫delete語句刪除指針指向的內存空間。
智能指針是一個類,這個類的構造函數中傳入一個普通指針,析構函數中釋放傳入的指針。智能指針的類都是棧上的對象,所以當函數(或程序)結束時會自動被釋放,
智能指針就是一種棧上創建的對象,函數退出時會調用其析構函數,這個析構函數裏面往往就是一堆計數之類的條件判斷,如果達到某個條件,就把真正指針指向的空間給釋放了。


注意事項:
不能將指針直接賦值給一個智能指針,一個是類,一個是指針。


常用的智能指針:
智能指針在C++11版本之後提供,包含在頭文件<memory>中,shared_ptr、unique_ptr、weak_ptr
1)std::auto_ptr,有很多問題。 不支持複製(拷貝構造函數)和賦值(operator =),但複製或賦值的時候不會提示出錯。所以可能會造成程序崩潰,比如
auto_ptr<string> p1(new string ("auto") ; //#1
auto_ptr<string> p2; //#2
p2 = p1; //#3
在語句#3中,p2接管string對象的所有權後,p1的所有權將被剝奪。前面說過,這是好事,可防止p1和p2的析構函數試圖刪同—個對象;
但如果程序隨後試圖使用p1,這將是件壞事,因爲p1不再指向有效的數據。如果再訪問p1指向的內容則會導致程序崩潰。
auto_ptr是C++98提供的解決方案,C+11已將將其摒棄,摒棄auto_ptr的原因,一句話總結就是:避免潛在的內存崩潰問題。


2) C++11引入的unique_ptr, 也不支持複製和賦值,但比auto_ptr好,直接賦值會編譯出錯。實在想賦值的話,需要使用:std::move。例如:
std::unique_ptr<int> p1(new int(5)) // #4
std::unique_ptr<int> p2 = p1; // 編譯會出錯 //#5
std::unique_ptr<int> p3 = std::move(p1); // 轉移所有權, 現在那塊內存歸p3所有, p1成爲無效的指針. //#6
編譯器認爲語句#5非法,因此,unique_ptr比auto_ptr更安全。
但unique_ptr還有更聰明的地方。 有時候,會將一個智能指針賦給另一個並不會留下危險的懸掛指針。當程序試圖將一個 unique_ptr 賦值給另一個時,如果源 unique_ptr 是個臨時右值,編譯器允許這麼做;如果源 unique_ptr 將存在一段時間,編譯器將禁止這麼做
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1; // #1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); // #2 allowed
其中#1留下懸掛的unique_ptr(pu1),這可能導致危害。而#2不會留下懸掛的unique_ptr,因爲它調用 unique_ptr 的構造函數,該構造函數創建的臨時對象在其所有權讓給 pu3 後就會被銷燬。這種隨情況而已的行爲表明,unique_ptr 優於允許兩種賦值的auto_ptr 。


3) C++11或boost的shared_ptr,基於引用計數的智能指針。可隨意賦值,直到內存的引用計數爲0的時候這個內存會被釋放。


4C++11或boost的weak_ptr,弱引用。 引用計數有一個問題就是互相引用形成環,這樣兩個指針指向的內存都無法釋放。需要手動打破循環引用或使用weak_ptr。顧名思義,weak_ptr是一個弱引用,只引用,不計數。如果一塊內存被shared_ptr和weak_ptr同時引用,當所有shared_ptr析構了之後,不管還有沒有weak_ptr引用該內存,內存也會被釋放。所以weak_ptr不保證它指向的內存一定是有效的,在使用之前需要檢查weak_ptr是否爲空指針。

智能指針的作用
C++程序設計中使用堆內存是非常頻繁的操作,堆內存的申請和釋放都由程序員自己管理。程序員自己管理堆內存可以提高了程序的效率,但是整體來說堆內存的管理是麻煩的,C++11中引入了智能指針的概念,方便管理堆內存。使用普通指針,容易造成堆內存泄露(忘記釋放),二次釋放,野指針,程序發生異常時內存泄露等問題等,使用智能指針能更好的管理堆內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章