unique_ptr 是 c++ 11 提供的用於防止記憶體洩漏的智慧型指標中的一種實現,獨享被管理物件指標所有權的智慧型指標。unique_ptr物件包裝乙個原始指標,並負責其生命週期。當該物件被銷毀時,會在其析構函式中釋放掉關聯的原始指標的動態記憶體,並刪除關聯的原始指標。這樣不管函式正常退出還是發生異常,都會釋放delete掉動態記憶體,不會造成記憶體的洩露。unique_ptr具有->
和*
運算子過載符,它可以像普通指標一樣使用。
unique_ptr 實現了獨享所有權的語義,不共享它的指標。它無法複製到其他 unique_ptr,無法通過值傳遞到函式,也無法用於需要副本的任何標準模板庫 (stl) 演算法,只能移動unique_ptr。乙個非空的std::unique_ptr總是擁有它所指向的資源。轉移乙個std::unique_ptr將會把所有權也從源指標轉移給目標指標(源指標被置空)。拷貝乙個std::unique_ptr將不被允許,因為如果你拷貝乙個std::unique_ptr,那麼拷貝結束後,這兩個std::unique_ptr都會指向相同的資源,它們都認為自己擁有這塊資源(所以都會企圖釋放)。因此std::unique_ptr是乙個僅能移動(move_only)的型別。當需要智慧型指標用於純 c++ 物件時,可使用unique_ptr,而當構造 unique_ptr 時,可使用make_unique 函式(c++14引入)。
unique_ptr 獨享所有權
unique_ptr物件始終是關聯的原始指標的唯一所有者。我們無法複製unique_ptr物件,它只能移動。
由於每個unique_ptr物件都是原始指標的唯一所有者,因此在其析構函式中它直接刪除關聯的指標,不需要任何參考計數。
1、如何建立unique_ptr
a. 建立乙個空的 unique_ptr 物件
建立乙個空的unique_ptr
物件,因為沒有與之關聯的原始指標,所以它是空的。
std::unique_ptrptr;
b. 使用原始指標建立 unique_ptr 物件,將乙個new 操作符返回的指標傳遞給unique_ptr的建構函式。
要建立非空的 unique_ptr 物件,需要在建立物件時在其建構函式中傳遞原始指標,即:
std::unique_ptrptr(new class());
std::unique_ptrptr = std::unique_ptr(new class());
不能通過賦值的方法建立物件,下面的這句是錯誤的
std::unique_ptrptr = new class(); // error !!
c. c++14引入了std::make_unique 建立 unique_ptr 物件,可以使用std::make_unique()函式來建立。
// 建立乙個unique_ptr例項
std::unique_ptrptr = std::make_unique(new int);
2、獲取被管理物件的指標
使用get()
函式獲取管理物件的指標。
class *p1 = ptr.get();
3、重置 unique_ptr 物件
在 unique_ptr 物件上呼叫reset()
函式將重置它,即它將釋放delete關聯的原始指標並使unique_ptr 物件為空。
ptr.reset();
4、檢查 unique_ptr 物件是否為空
有兩種方法可以檢查 unique_ptr 物件是否為空或者是否有與之關聯的原始指標。
// 方法1
if(!ptr)
std::cout<<"ptr is empty"<2、無法進行複製構造和賦值操作
unique_ptr沒有copy建構函式,不支援普通的拷貝和賦值操作。
int main()
3、可以進行移動構造和移動賦值操作
unique_ptr雖然沒有支援普通的拷貝和賦值操作,但卻提供了一種移動機制來將指標的所有權從乙個unique_ptr轉移給另乙個unique_ptr。如果需要轉移所有權,可以使用std::move()函式。
示例:
int main()
4、可以返回unique_ptr
unique_ptr不支援拷貝操作,但卻有乙個例外:可以從函式中返回乙個unique_ptr。
示例:
unique_ptrclone(int p)
int main()
5、unique_ptr 物件不可複製
由於 unique_ptr 不可複製,只能移動。因此,我們無法通過複製建構函式或賦值運算子建立unique_ptr物件的副本。
// 編譯錯誤 : unique_ptr 不能複製
std::unique_ptrptr3 = ptr2; // compile error
// 編譯錯誤 : unique_ptr 不能複製
ptr = ptr2; //compile error
6、轉移 unique_ptr 物件的所有權
我們無法複製 unique_ptr 物件,但我們可以轉移它們。這意味著 unique_ptr 物件可以將關聯的原始指標的所有權轉移到另乙個 unique_ptr 物件。讓我們通過乙個例子來理解:
// 通過原始指標建立 ptr2
std::unique_ptrtaskptr2(new class(55));
// 把taskptr2中關聯指標的所有權轉移給taskptr4
std::unique_ptrptr4 = std::move(ptr2);
// 現在taskptr2關聯的指標為空
if(ptr2 == nullptr)
std::cout<<"ptr2 is empty"7、釋放關聯的原始指標
在 unique_ptr 物件上呼叫release()
將釋放其關聯的原始指標的所有權,並返回原始指標。這裡是釋放所有權,並沒有delete原始指標,reset()
會delete原始指標。
std::unique_ptrptr5(new class(args,...));
// 不為空
if(ptr5 != nullptr)
std::cout<<"ptr5 is not empty"<8、unique_ptr使用場景
8.1 為動態申請的資源提供異常安全保證
我們先來看看下面這一段**:
void func()
這是我們傳統的寫法:當我們動態申請記憶體後,有可能我們接下來的**由於丟擲異常或者提前退出(if語句)而沒有執行delete操作。
解決的方法是使用unique_ptr來管理動態記憶體,只要unique_ptr指標建立成功,其析構函式都會被呼叫。確保動態資源被釋放。
void func()
8.2 返回函式內動態申請資源的所有權
unique_ptrfunc(int p)
int main()
8.3 在容器中儲存指標
int main()
8.4 管理動態陣列
標準庫提供了乙個可以管理動態陣列的unique_ptr版本。
int main()
); p[0] = 0; // 過載了operator
}
總結
new出來的物件是位於堆記憶體上的,必須呼叫delete才能釋放其記憶體。
unique_ptr 是乙個裝指標的容器,且擁有關聯指標的唯一所有權,作為普通變數使用時系統分配物件到棧記憶體上,超出作用域時會自動析構,unique_ptr物件的析構函式中會delete其關聯指標,這樣就相當於替我們執行了delete堆記憶體上的物件。
成員函式
作用reset()
重置unique_ptr為空,delete其關聯的指標。
release()
不delete關聯指標,並返回關聯指標。釋放關聯指標的所有權,unique_ptr為空。
get()
僅僅返回關聯指標
unique_ptr不能直接複製,必須使用std::move()
轉移其管理的指標,轉移後原 unique_ptr 為空。
**:
C 11 建立和使用 unique ptr
unique ptr 不共享它的指標。它無法複製到其他 unique ptr,無法通過值傳遞到函式,也無法用於需要副本的任何標準模板庫 stl 演算法。只能移動unique ptr。這意味著,記憶體資源所有權將轉移到另一 unique ptr,並且原始 unique ptr 不再擁有此資源。我們建議...
C 11 建立和使用 unique ptr
unique ptr 不共享它的指標。它無法複製到其他unique ptr,無法通過值傳遞到函式,也無法用於需要副本的任何標準模板庫 stl 演算法。只能移動unique ptr。這意味著,記憶體資源所有權將轉移到另一unique ptr,並且原始unique ptr不再擁有此資源。我們建議你將物件...
C 11 建立和使用 unique ptr
c 11 建立和使用 unique ptr unique ptr 不共享它的指標。它無法複製到其他 unique ptr,無法通過值傳遞到函式,也無法用於需要副本的任何標準模板庫 stl 演算法。只能移動unique ptr。這意味著,記憶體資源所有權將轉移到另一 unique ptr,並且原始 u...