在《
C++11 shared_ptr智能指針》的基礎上,本節繼續講解 C++11 標准提供的另一種智能指針,即 unique_ptr 智能指針。
作為智能指針的一種,unique_ptr 指針自然也具備“在適當時機自動釋放堆內存空間”的能力。和 shared_ptr 指針最大的不同之處在於,unique_ptr 指針指向的堆內存無法同其它 unique_ptr 共享,也就是說,每個 unique_ptr 指針都獨自擁有對其所指堆內存空間的所有權。
1) 通過以下 2 種方式,可以創建出空的 unique_ptr 指針:
2) 創建 unique_ptr 指針的同時,也可以明確其指向。例如:
由此就創建出了一個 p3 智能指針,其指向的是可容納 1 個整數的堆存儲空間。
3) 基於 unique_ptr 類型指針不共享各自擁有的堆內存,因此 C++11 標准中的 unique_ptr 模板類沒有提供拷貝構造函數,只提供了移動構造函數。例如:
值得一提的是,對於調用移動構造函數的 p4 和 p5 來說,p5 將獲取 p4 所指堆空間的所有權,而 p4 將變成空指針(nullptr)。
4) 默認情況下,unique_ptr 指針采用 std::default_delete<T> 方法釋放堆內存。當然,我們也可以自定義符合實際場景的釋放規則。值得一提的是,和 shared_ptr 指針不同,為 unique_ptr 自定義釋放規則,只能采用函數對象的方式。例如:
下面程序給大家演示了 unique_ptr 智能指針的基本用法,以及該模板類提供了一些成員方法的用法:
程序執行結果為:
作為智能指針的一種,unique_ptr 指針自然也具備“在適當時機自動釋放堆內存空間”的能力。和 shared_ptr 指針最大的不同之處在於,unique_ptr 指針指向的堆內存無法同其它 unique_ptr 共享,也就是說,每個 unique_ptr 指針都獨自擁有對其所指堆內存空間的所有權。
unique_ptr 智能指針是以模板類的形式提供的,unique_ptr<T>(T 為指針所指數據的類型)定義在這也就意味着,每個 unique_ptr 指針指向的堆內存空間的引用計數,都只能為 1,一旦該 unique_ptr 指針放棄對所指堆內存空間的所有權,則該空間會被立即釋放回收。
<memory>
頭文件,並位於 std 命名空間中。因此,要想使用 unique_ptr 類型指針,程序中應首先包含如下 2 條語句:
- #include <memory>
- using namespace std;
第 2 句並不是必須的,可以不添加,則后續在使用 unique_ptr 指針時,必須標注
std::
。
unique_ptr智能指針的創建
考慮到不同實際場景的需要,unique_ptr<T> 模板類提供了多個實用的構造函數,這里給讀者列舉了幾種常用的構造 unique_ptr 智能指針的方式。1) 通過以下 2 種方式,可以創建出空的 unique_ptr 指針:
- std::unique_ptr<int> p1();
- std::unique_ptr<int> p2(nullptr);
2) 創建 unique_ptr 指針的同時,也可以明確其指向。例如:
- std::unique_ptr<int> p3(new int);
和可以用 make_shared<T>() 模板函數初始化 shared_ptr 指針不同,C++11 標准中並沒有為 unique_ptr 類型指針添加類似的模板函數。
3) 基於 unique_ptr 類型指針不共享各自擁有的堆內存,因此 C++11 標准中的 unique_ptr 模板類沒有提供拷貝構造函數,只提供了移動構造函數。例如:
- std::unique_ptr<int> p4(new int);
- std::unique_ptr<int> p5(p4);//錯誤,堆內存不共享
- std::unique_ptr<int> p5(std::move(p4));//正確,調用移動構造函數
4) 默認情況下,unique_ptr 指針采用 std::default_delete<T> 方法釋放堆內存。當然,我們也可以自定義符合實際場景的釋放規則。值得一提的是,和 shared_ptr 指針不同,為 unique_ptr 自定義釋放規則,只能采用函數對象的方式。例如:
- //自定義的釋放規則
- struct myDel
- {
- void operator()(int *p) {
- delete p;
- }
- };
- std::unique_ptr<int, myDel> p6(new int);
- //std::unique_ptr<int, myDel> p6(new int, myDel());
unique_ptr<T>模板類提供的成員方法
為了方便用戶使用 unique_ptr 智能指針,unique_ptr<T> 模板類還提供有一些實用的成員方法,它們各自的功能如表 1 所示。成員函數名 | 功 能 |
---|---|
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 智能指針的基本用法,以及該模板類提供了一些成員方法的用法:
- #include <iostream>
- #include <memory>
- using namespace std;
- int main()
- {
- std::unique_ptr<int> p5(new int);
- *p5 = 10;
- // p 接收 p5 釋放的堆內存
- int * p = p5.release();
- cout << *p << endl;
- //判斷 p5 是否為空指針
- if (p5) {
- cout << "p5 is not nullptr" << endl;
- }
- else {
- cout << "p5 is nullptr" << endl;
- }
- std::unique_ptr<int> p6;
- //p6 獲取 p 的所有權
- p6.reset(p);
- cout << *p6 << endl;;
- return 0;
- }
10
p5 is nullptr
10