C++11 unique_ptr智能指針詳解


在《 C++11 shared_ptr智能指針》的基礎上,本節繼續講解 C++11 標准提供的另一種智能指針,即 unique_ptr 智能指針。

作為智能指針的一種,unique_ptr 指針自然也具備“在適當時機自動釋放堆內存空間”的能力。和 shared_ptr 指針最大的不同之處在於,unique_ptr 指針指向的堆內存無法同其它 unique_ptr 共享,也就是說,每個 unique_ptr 指針都獨自擁有對其所指堆內存空間的所有權。

這也就意味着,每個 unique_ptr 指針指向的堆內存空間的引用計數,都只能為 1,一旦該 unique_ptr 指針放棄對所指堆內存空間的所有權,則該空間會被立即釋放回收。

unique_ptr 智能指針是以模板類的形式提供的,unique_ptr<T>(T 為指針所指數據的類型)定義在 <memory>頭文件,並位於 std 命名空間中。因此,要想使用 unique_ptr 類型指針,程序中應首先包含如下 2 條語句:
  1. #include <memory>
  2. using namespace std;

第 2 句並不是必須的,可以不添加,則后續在使用 unique_ptr 指針時,必須標注std::

unique_ptr智能指針的創建

考慮到不同實際場景的需要,unique_ptr<T> 模板類提供了多個實用的構造函數,這里給讀者列舉了幾種常用的構造 unique_ptr 智能指針的方式。

1) 通過以下  2 種方式,可以創建出空的 unique_ptr 指針:
  1. std::unique_ptr<int> p1();
  2. std::unique_ptr<int> p2(nullptr);

2) 創建 unique_ptr 指針的同時,也可以明確其指向。例如:
  1. std::unique_ptr<int> p3(new int);
由此就創建出了一個 p3 智能指針,其指向的是可容納 1 個整數的堆存儲空間。

和可以用 make_shared<T>() 模板函數初始化 shared_ptr 指針不同,C++11 標准中並沒有為 unique_ptr 類型指針添加類似的模板函數。


3) 基於 unique_ptr 類型指針不共享各自擁有的堆內存,因此 C++11 標准中的 unique_ptr 模板類沒有提供拷貝構造函數,只提供了移動構造函數。例如:
  1. std::unique_ptr<int> p4(new int);
  2. std::unique_ptr<int> p5(p4);//錯誤,堆內存不共享
  3. std::unique_ptr<int> p5(std::move(p4));//正確,調用移動構造函數
值得一提的是,對於調用移動構造函數的 p4 和 p5 來說,p5 將獲取 p4 所指堆空間的所有權,而 p4 將變成空指針(nullptr)。

4) 默認情況下,unique_ptr 指針采用 std::default_delete<T> 方法釋放堆內存。當然,我們也可以自定義符合實際場景的釋放規則。值得一提的是,和 shared_ptr 指針不同,為 unique_ptr 自定義釋放規則,只能采用函數對象的方式。例如:
  1. //自定義的釋放規則
  2. struct myDel
  3. {
  4. void operator()(int *p) {
  5. delete p;
  6. }
  7. };
  8. std::unique_ptr<int, myDel> p6(new int);
  9. //std::unique_ptr<int, myDel> p6(new int, myDel());

unique_ptr<T>模板類提供的成員方法

為了方便用戶使用 unique_ptr 智能指針,unique_ptr<T> 模板類還提供有一些實用的成員方法,它們各自的功能如表 1 所示。

表 1 unique_ptr指針可調用的成員函數
成員函數名 功 能
operator*() 獲取當前 unique_ptr 指針指向的數據。
operator->() 重載 -> 號,當智能指針指向的數據類型為自定義的結構體時,通過 -> 運算符可以獲取其內部的指定成員。
operator =() 重載了 = 賦值號,從而可以將 nullptr 或者一個右值 unique_ptr 指針直接賦值給當前同類型的 unique_ptr 指針。
operator []() 重載了 [] 運算符,當 unique_ptr 指針指向一個數組時,可以直接通過 [] 獲取指定下標位置處的數據。
get() 獲取當前 unique_ptr 指針內部包含的普通指針。
get_deleter() 獲取當前 unique_ptr 指針釋放堆內存空間所用的規則。
operator bool() unique_ptr 指針可直接作為 if 語句的判斷條件,以判斷該指針是否為空,如果為空,則為 false;反之為 true。
release() 釋放當前 unique_ptr 指針對所指堆內存的所有權,但該存儲空間並不會被銷毀。
reset(p) 其中 p 表示一個普通指針,如果 p 為 nullptr,則當前 unique_ptr 也變成空指針;反之,則該函數會釋放當前 unique_ptr 指針指向的堆內存(如果有),然后獲取 p 所指堆內存的所有權(p 為 nullptr)。
swap(x) 交換當前 unique_ptr 指針和同類型的 x 指針。

除此之外,C++11標准還支持同類型的 unique_ptr 指針之間,以及 unique_ptr 和 nullptr 之間,做 ==,!=,<,<=,>,>= 運算。


下面程序給大家演示了 unique_ptr 智能指針的基本用法,以及該模板類提供了一些成員方法的用法:
  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. int main()
  5. {
  6. std::unique_ptr<int> p5(new int);
  7. *p5 = 10;
  8. // p 接收 p5 釋放的堆內存
  9. int * p = p5.release();
  10. cout << *p << endl;
  11. //判斷 p5 是否為空指針
  12. if (p5) {
  13. cout << "p5 is not nullptr" << endl;
  14. }
  15. else {
  16. cout << "p5 is nullptr" << endl;
  17. }
  18. std::unique_ptr<int> p6;
  19. //p6 獲取 p 的所有權
  20. p6.reset(p);
  21. cout << *p6 << endl;;
  22. return 0;
  23. }
程序執行結果為:

10
p5 is nullptr
10


免責聲明!

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



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