參考鏈接
- std::unique_ptr
介紹
- 定義位于頭文件<memory>
- std::unique_ptr 是通過指針占有并管理另一對象,并在 unique_ptr 離開作用域時釋放該對象的智能指針。 在下列兩者之一發生時用關聯的刪除器釋放對象:1,銷毀了管理的 unique_ptr 對象;2, 通過 operator= 或 reset() 賦值另一指針給管理的 unique_ptr 對象。
- 通過調用 get_deleter()(ptr) ,用潛在為用戶提供的刪除器釋放對象。默認刪除器用 delete 運算符,它銷毀對象并解分配內存。
- unique_ptr 亦可以不占有對象,該情況下稱它為空 (empty)。 std::unique_ptr 有兩個版本: 1) 管理單個對象(例如以 new 分配) 2) 管理動態分配的對象數組(例如以 new[] 分配)
- 類滿足可移動構造?(MoveConstructible)?和可移動賦值?(MoveAssignable)?的要求,但不滿足可復制構造?(CopyConstructible)?或可復制賦值?(CopyAssignable)?的要求。
- 只有非 const 的?
unique_ptr
?能轉移被管理對象的所有權給另一?unique_ptr
?。若對象的生存期為?const?std::unique_ptr?所管理,則它被限定在創建指針的作用域中。 std::unique_ptr
?常用于管理對象的生存期,包含:- 通過正常退出和經由異常退出兩者上的受保證刪除,提供異常安全,給處理擁有動態生存期的對象的類和函數
- 傳遞獨占的擁有動態生存期的對象的所有權到函數
- 從函數獲得獨占的擁有動態生存期對象的所有權
- 作為具移動容器的元素類型,例如保有指向動態分配對象的指針的?std::vector?(例如,若想要多態行為)
std::unique_ptr
?可為不完整類型?T
?構造,例如用于改善用作?pImpl 手法中柄的用途。若使用默認刪除器,則?T
?必須在代碼中調用刪除器點處完整,這發生于析構函數、移動賦值運算符和?std::unique_ptr
?的?reset
?成員函數中。(相反地,?std::shared_ptr?不能從指向不完整類型的裸指針構造,但可于?T
?不完整處銷毀)。注意若?T
?是類模板特化,則以?unique_ptr
?為運算數的使用,如?!p?,因?ADL?而要求?T
?的形參完整。- 若?
T
?是某基類?B
?的派生類,則?std::unique_ptr<T>?可隱式轉換為?std::unique_ptr<B>。產生的?std::unique_ptr<B>?的默認刪除器將使用?B
?的?operator delete?,這導致未定義行為,除非?B
?的析構函數為虛。注意?std::shared_ptr?表現有別:?std::shared_ptr<B>?將使用類型?T
?的?operator delete?,而且即使?B
?的析構函數非虛,也會正確刪除被占有對象。 - 不同于?std::shared_ptr?,?
std::unique_ptr
?可通過任何滿足可空指針?(NullablePointer)?的定制柄類型管理對象。例如,這允許管理位于共享內存,但提供定義?typedef?boost::offset_ptr?pointer;
?或其他綴飾指針的?Deleter
?的對象。
參考代碼
#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>struct B {virtual void bar() { std::cout << "B::bar\n"; }virtual ~B() = default;
};
struct D : B
{D() { std::cout << "D::D\n"; }~D() { std::cout << "D::~D\n"; }void bar() override { std::cout << "D::bar\n"; }
};// 消費 unique_ptr 的函數能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{p->bar();return p;
}void close_file(std::FILE* fp) { std::fclose(fp); }int main()
{std::cout << "unique ownership semantics demo\n";{auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptrauto q = pass_through(std::move(p)); assert(!p); // 現在 p 不占有任何內容并保有空指針q->bar(); // 而 q 占有 D 對象} // ~D 調用于此std::cout << "Runtime polymorphism demo\n";{std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr// 作為指向基類的指針p->bar(); // 虛派發std::vector<std::unique_ptr<B>> v; // unique_ptr 能存儲于容器v.push_back(std::make_unique<D>());v.push_back(std::move(p));v.emplace_back(new D);for(auto& p: v) p->bar(); // 虛派發} // ~D called 3 timesstd::cout << "Custom deleter demo\n";std::ofstream("demo.txt") << 'x'; // 準備要讀的文件{std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),close_file);if(fp) // fopen 可以打開失敗;該情況下 fp 保有空指針std::cout << (char)std::fgetc(fp.get()) << '\n';} // fclose() 調用于此,但僅若 FILE* 不是空指針// (即 fopen 成功)std::cout << "Custom lambda-expression deleter demo\n";{std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr){std::cout << "destroying from a custom deleter...\n";delete ptr;}); // p 占有 Dp->bar();} // 調用上述 lambda 并銷毀 Dstd::cout << "Array form of unique_ptr demo\n";{std::unique_ptr<D[]> p{new D[3]};} // 調用 ~D 3 次
}
?