std::unique_ptr 是 C++11 引入的獨占式智能指針,取代已棄用的 auto_ptr。它嚴格遵循單一所有權原則:同一時刻只能有一個 unique_ptr 管理某對象,禁止拷貝,僅支持移動語義轉移所有權。零開銷、無控制塊、適合獨占資源場景。
| 特性 | unique_ptr | shared_ptr |
|---|---|---|
| 所有權 | 獨占 | 共享 |
| 拷貝構造/賦值 | 刪除(編譯錯誤) | 允許 |
| 移動構造/賦值 | 允許(轉移所有權) | 允許 |
| 控制塊 | 無 | 有(引用計數、弱計數、刪除器、分配器) |
| 數組支持 | 原生 unique_ptr<T[]> | 需自定義刪除器 |
| 線程安全 | 無共享狀態,天然安全 | 控制塊原子操作 |
| 開銷 | 極小(一個指針大小) | 較大(控制塊、原子操作) |
unique_ptr<T> p(new T)、make_unique<T>(args...) (C++14)release() 返回裸指針並置空,調用者負責刪除reset(new T) 刷舊換新,reset() 釋放get()(不轉移所有權)std::move(p1) → p2,p1 置空if (p)unique_ptr<int[]> arr(new int[5]),支持 arr[i]unique_ptr 通過模板參數指定刪除器類型,刪除器作為成員存儲(空基優化):
// 函數指針刪除器
void my_deleter(int* p) { delete p; }
std::unique_ptr<int, void(*)(int*)> p1(new int, my_deleter);
// Lambda 刪除器 (需捕獲無狀態)
auto del = [](int* p) { delete p; };
std::unique_ptr<int, decltype(del)> p2(new int, del);
// 結構體刪除器
struct Deleter { void operator()(int* p) { delete p; } };
std::unique_ptr<int, Deleter> p3(new int);
struct Foo {
Foo() { std::cout << "Foo::Foo\n"; }
~Foo() { std::cout << "Foo::~Foo\n"; }
void bar() { std::cout << "Foo::bar\n"; }
};
int test_unique_ptr1() {
std::unique_ptr<Foo> p1(new Foo);
if (p1) p1->bar();
{ // 內部作用域
std::unique_ptr<Foo> p2(std::move(p1)); // p2 接管
p1 = std::move(p2); // 權限回歸 p1
std::cout << "destroying p2...\n";
} // p2 銷毀,但對象仍存活(p1 持有)
if (p1) p1->bar(); // 繼續使用
return 0; // p1 銷毀,對象釋放
}
int test_unique_ptr2() {
std::default_delete<int> d;
std::unique_ptr<int> u1; // 空
std::unique_ptr<int> u2(nullptr); // 空
std::unique_ptr<int> u3(new int); // 默認刪除器
std::unique_ptr<int> u4(new int, d); // 自定義刪除器
std::unique_ptr<int> u5(new int, std::default_delete<int>());
std::unique_ptr<int> u6(std::move(u5)); // 移動構造
std::unique_ptr<int> u7(std::move(u6));
std::unique_ptr<int> u8(std::auto_ptr<int>(new int)); // 從 auto_ptr 轉移 (C++11)
// 狀態檢查
auto print = [](const char* name, const std::unique_ptr<int>& p) {
std::cout << name << ": " << (p ? "not null" : "null") << '\n';
};
print("u1", u1); print("u2", u2); print("u3", u3);
print("u4", u4); print("u5", u5); print("u6", u6);
print("u7", u7); print("u8", u8);
return 0;
}
int test_unique_ptr4() {
// 函數參數傳遞(移動)
void sink(std::unique_ptr<Foo> p) { ... }
std::unique_ptr<Foo> source() { return std::make_unique<Foo>(); }
auto pmain = source(); // C++17 RVO 或移動
sink(std::move(pmain)); // 必須移動
// 容器存儲
std::vector<std::unique_ptr<int>> vi;
vi.push_back(std::make_unique<int>(0));
vi.push_back(std::make_unique<int>(3));
vi.push_back(std::make_unique<int>(2));
std::sort(vi.begin(), vi.end(),
[](const auto& a, const auto& b) { return *a < *b; });
// 結果:{0, 2, 3}
// 數組支持
std::unique_ptr<int[]> arr(new int[5]);
arr[0] = 5; // operator[] 可用
// *arr 編譯錯誤:數組版本無 operator*
return 0;
}
// 管理 FILE*
struct FileDeleter {
void operator()(FILE* f) { if (f) fclose(f); }
};
std::unique_ptr<FILE, FileDeleter> fp(fopen("test.txt", "w"));
// 管理 Windows HANDLE
struct HandleDeleter {
void operator()(HANDLE h) { if (h) CloseHandle(h); }
};
std::unique_ptr<void, HandleDeleter> h(CreateFile(...));
unique_ptr:單一所有權場景,零開銷,意圖明確unique_ptr:std::make_unique<T>(args) (C++14) 或手工構造shared_ptr:避免過早共享new/delete:RAII 管理所有資源unique_ptr<T[]>:自動調用 delete[]unique_ptr:配合移動語義、算法完美工作
GitHub 完整代碼:https://github.com/fengbingchun/Messy_Test