C++四個智能指針的使用小結(jié)
一、先搞懂:為什么需要智能指針?
C++ 原生指針(裸指針)最大的問題是手動管理內(nèi)存容易出錯,比如:
- 忘記釋放內(nèi)存 → 內(nèi)存泄漏;
- 提前釋放內(nèi)存 → 野指針(訪問已釋放的內(nèi)存);
- 重復(fù)釋放內(nèi)存 → 程序崩潰;
- 異常場景下(比如函數(shù)中途拋異常),釋放代碼執(zhí)行不到 → 內(nèi)存泄漏。
智能指針的核心是利用 RAII 機(jī)制(資源獲取即初始化):把內(nèi)存管理綁定到智能指針的生命周期,當(dāng)智能指針超出作用域(如函數(shù)結(jié)束、對象銷毀)時,自動調(diào)用析構(gòu)函數(shù)釋放內(nèi)存,徹底避免手動管理的問題。
二、C++ 四大智能指針詳解(附代碼示例)
C++ 標(biāo)準(zhǔn)庫(<memory> 頭文件)提供了 4 種智能指針,其中 auto_ptr 已被廢棄,重點掌握后 3 種:
| 智能指針 | 核心特性 | 適用場景 | 線程安全 |
|---|---|---|---|
| auto_ptr | 獨占所有權(quán),已廢棄 | 無(C++11 后用 unique_ptr 替代) | 否 |
| unique_ptr | 獨占所有權(quán),不可拷貝 | 單個對象/數(shù)組的獨占管理 | 否 |
| shared_ptr | 共享所有權(quán),引用計數(shù) | 多個對象共享同一塊內(nèi)存 | 引用計數(shù)線程安全,對象本身否 |
| weak_ptr | 弱引用,不增加引用計數(shù) | 解決 shared_ptr 循環(huán)引用 | 否 |
1.auto_ptr(廢棄!僅作了解)
- 問題:拷貝時會轉(zhuǎn)移所有權(quán)(原指針變?yōu)榭眨瑯O易導(dǎo)致野指針,C++11 已被 unique_ptr 取代。
- 反例(為什么廢棄):
#include <memory> #include <iostream> using namespace std; int main() { auto_ptr<int> p1(new int(10)); auto_ptr<int> p2 = p1; // 拷貝后,p1 所有權(quán)轉(zhuǎn)移給 p2,p1 變?yōu)榭? cout << *p2 << endl; // 正常輸出 10 // cout << *p1 << endl; // 崩潰!p1 是空指針 return 0; }
2.unique_ptr(最常用!獨占式智能指針)
- 核心:保證同一時間只有一個
unique_ptr指向一塊內(nèi)存,不可拷貝,僅可移動(std::move)。 - 優(yōu)勢:輕量級(性能接近裸指針),支持管理數(shù)組(
unique_ptr<int[]>)。 - 示例:
#include <memory> #include <iostream> using namespace std; int main() { // 1. 基本使用:獨占內(nèi)存,超出作用域自動釋放 unique_ptr<int> p(new int(10)); cout << *p << endl; // 輸出 10 // 2. 不可拷貝(編譯報錯) // unique_ptr<int> p2 = p; // 3. 可移動(轉(zhuǎn)移所有權(quán)) unique_ptr<int> p3 = move(p); // cout << *p << endl; // 崩潰!p 已無所有權(quán) cout << *p3 << endl; // 輸出 10 // 4. 管理數(shù)組(自動調(diào)用 delete[]) unique_ptr<int[]> arr(new int[3]{1,2,3}); cout << arr[1] << endl; // 輸出 2 return 0; // p3、arr 超出作用域,自動釋放內(nèi)存 }
3.shared_ptr(共享式智能指針)
- 核心:通過引用計數(shù)管理內(nèi)存:每多一個
shared_ptr指向同一塊內(nèi)存,計數(shù)+1;指針銷毀時計數(shù)-1;計數(shù)為 0 時,自動釋放內(nèi)存。 - 注意:不能用裸指針初始化多個
shared_ptr(會導(dǎo)致重復(fù)釋放),推薦用make_shared初始化(更高效)。 - 示例:
#include <memory> #include <iostream> using namespace std; int main() { // 1. 初始化(推薦 make_shared,避免內(nèi)存碎片) shared_ptr<int> p1 = make_shared<int>(10); cout << p1.use_count() << endl; // 輸出 1(引用計數(shù)) // 2. 拷貝:引用計數(shù)+1 shared_ptr<int> p2 = p1; cout << p1.use_count() << endl; // 輸出 2 cout << *p2 << endl; // 輸出 10 // 3. 銷毀一個指針:引用計數(shù)-1 p1.reset(); // 手動釋放 p1 的所有權(quán) cout << p2.use_count() << endl; // 輸出 1 return 0; // p2 超出作用域,計數(shù)變?yōu)?0,內(nèi)存釋放 }
4.weak_ptr(弱引用指針,解決循環(huán)引用)
核心:指向 shared_ptr 管理的內(nèi)存,但不增加引用計數(shù),不會阻止內(nèi)存釋放;需先轉(zhuǎn)為 shared_ptr 才能訪問對象。
解決的問題:shared_ptr 循環(huán)引用(如 A 指向 B,B 指向 A)會導(dǎo)致引用計數(shù)永遠(yuǎn)不為 0,內(nèi)存泄漏,weak_ptr 可破解。
示例(循環(huán)引用問題 + 解決):
#include <memory>
using namespace std;
// 循環(huán)引用問題(內(nèi)存泄漏)
struct A { shared_ptr<B> b; ~A() { cout << "A 析構(gòu)" << endl; } };
struct B { shared_ptr<A> a; ~B() { cout << "B 析構(gòu)" << endl; } };
// 用 weak_ptr 解決循環(huán)引用
struct C { shared_ptr<D> d; ~C() { cout << "C 析構(gòu)" << endl; } };
struct D { weak_ptr<C> c; ~D() { cout << "D 析構(gòu)" << endl; } };
int main() {
// 1. 循環(huán)引用:析構(gòu)函數(shù)不會執(zhí)行,內(nèi)存泄漏
auto a = make_shared<A>();
auto b = make_shared<B>();
a->b = b;
b->a = a;
// 2. 用 weak_ptr 解決:析構(gòu)函數(shù)正常執(zhí)行
auto c = make_shared<C>();
auto d = make_shared<D>();
c->d = d;
d->c = c; // D 用 weak_ptr 指向 C,不增加引用計數(shù)
return 0;
}輸出:
D 析構(gòu)
C 析構(gòu)
(A、B 的析構(gòu)函數(shù)未執(zhí)行,C、D 正常執(zhí)行)
三、智能指針的核心使用原則
- 優(yōu)先用
unique_ptr:性能最好,獨占所有權(quán),滿足大部分場景; - 需要共享時用
shared_ptr:避免循環(huán)引用,搭配weak_ptr; - 禁止用裸指針初始化多個
shared_ptr:會導(dǎo)致重復(fù)釋放; - 不要用智能指針管理非堆內(nèi)存(如棧上的對象):析構(gòu)時會調(diào)用
delete,導(dǎo)致崩潰; - 自定義刪除器:如果管理的資源不是
new分配的(如malloc、文件句柄),需自定義刪除器:// 示例:管理文件句柄(自定義刪除器關(guān)閉文件) shared_ptr<FILE> fp(fopen("test.txt", "r"), [](FILE* f) { fclose(f); });
總結(jié)
- 智能指針的核心價值是自動管理內(nèi)存,解決裸指針的內(nèi)存泄漏、野指針等問題;
unique_ptr是首選(獨占、高效),shared_ptr用于共享場景,weak_ptr解決循環(huán)引用;auto_ptr已廢棄,切勿使用;- 本質(zhì)是 RAII 機(jī)制:把內(nèi)存釋放邏輯封裝到析構(gòu)函數(shù),利用 C++ 自動調(diào)用析構(gòu)的特性,實現(xiàn)“不用手動釋放”。
智能指針是C++ RAII(資源獲取即初始化)機(jī)制的核心實現(xiàn),旨在解決手動管理指針導(dǎo)致的內(nèi)存泄漏、野指針、重復(fù)釋放等問題。以下先深度解析shared_ptr的實現(xiàn)原理(基于參考回答優(yōu)化),再講解unique_ptr和weak_ptr的實現(xiàn)邏輯與核心差異。
一、shared_ptr 實現(xiàn)詳解(帶完整可運行代碼)
shared_ptr的核心是引用計數(shù):多個shared_ptr共享同一個底層指針,引用計數(shù)記錄當(dāng)前指針被引用的次數(shù),僅當(dāng)計數(shù)為0時,才真正釋放底層內(nèi)存。
1. 核心設(shè)計思路
| 核心成員 | 作用 |
|---|---|
| T* ptr | 指向底層資源的原始指針 |
| int* use_count | 引用計數(shù)的指針(所有共享對象指向同一塊內(nèi)存,保證計數(shù)共享) |
| 拷貝構(gòu)造/賦值重載 | 增加引用計數(shù) |
| 析構(gòu)函數(shù) | 減少引用計數(shù),計數(shù)為0時釋放資源+計數(shù)內(nèi)存 |
2. 完整實現(xiàn)(修復(fù)參考回答的bug,補(bǔ)充線程安全)
#include <iostream>
#include <mutex> // 引入互斥鎖保證線程安全
using namespace std;
template <typename T>
class SharedPtr {
private:
T* ptr; // 底層資源指針
int* use_count; // 引用計數(shù)(指針形式,保證所有對象共享)
mutex* mtx; // 互斥鎖(保證多線程下計數(shù)操作原子性)
// 私有輔助函數(shù):釋放當(dāng)前資源
void release() {
lock_guard<mutex> lock(*mtx); // 加鎖保證線程安全
if (--(*use_count) == 0) { // 引用計數(shù)減1,若為0則釋放資源
delete ptr; // 釋放底層內(nèi)存
delete use_count; // 釋放計數(shù)內(nèi)存
delete mtx; // 釋放鎖內(nèi)存
ptr = nullptr;
use_count = nullptr;
mtx = nullptr;
}
}
public:
// 1. 構(gòu)造函數(shù):接收原始指針
SharedPtr(T* p = nullptr) : ptr(p) {
try {
use_count = new int(1); // 初始計數(shù)為1
mtx = new mutex(); // 初始化鎖
} catch (...) { // 內(nèi)存分配失敗,釋放資源避免泄漏
delete ptr;
ptr = nullptr;
throw; // 拋出異常,讓上層處理
}
}
// 2. 拷貝構(gòu)造函數(shù):共享資源,計數(shù)+1
SharedPtr(const SharedPtr<T>& other) {
ptr = other.ptr;
use_count = other.use_count;
mtx = other.mtx;
// 加鎖更新計數(shù)(多線程安全)
lock_guard<mutex> lock(*mtx);
++(*use_count);
}
// 3. 賦值運算符重載:先釋放自己的資源,再共享對方的資源
SharedPtr<T>& operator=(const SharedPtr<T>& other) {
// 防止自賦值(p = p)
if (this == &other) return *this;
// 第一步:釋放當(dāng)前對象持有的資源
release();
// 第二步:共享新對象的資源,計數(shù)+1
ptr = other.ptr;
use_count = other.use_count;
mtx = other.mtx;
lock_guard<mutex> lock(*mtx);
++(*use_count);
return *this;
}
// 4. 析構(gòu)函數(shù):計數(shù)-1,計數(shù)為0則釋放資源
~SharedPtr() {
if (use_count != nullptr) { // 避免重復(fù)釋放
release();
}
}
// 5. 重載解引用運算符:模擬原始指針行為
T& operator*() const {
if (ptr == nullptr) {
throw runtime_error("解引用空指針");
}
return *ptr;
}
// 6. 重載->運算符:模擬原始指針行為
T* operator->() const {
if (ptr == nullptr) {
throw runtime_error("訪問空指針成員");
}
return ptr;
}
// 7. 獲取引用計數(shù)
int get_count() const {
lock_guard<mutex> lock(*mtx);
return *use_count;
}
// 8. 獲取原始指針(謹(jǐn)慎使用)
T* get() const {
return ptr;
}
// 禁用移動構(gòu)造/賦值(簡化版,C++11后可實現(xiàn))
SharedPtr(SharedPtr<T>&&) = delete;
SharedPtr<T>& operator=(SharedPtr<T>&&) = delete;
};
// 測試代碼
int main() {
SharedPtr<int> p1(new int(10));
cout << "p1計數(shù):" << p1.get_count() << endl; // 輸出1
cout << "*p1 = " << *p1 << endl; // 輸出10
SharedPtr<int> p2 = p1;
cout << "p1計數(shù):" << p1.get_count() << endl; // 輸出2
cout << "p2計數(shù):" << p2.get_count() << endl; // 輸出2
*p2 = 20;
cout << "*p1 = " << *p1 << endl; // 輸出20(共享資源)
SharedPtr<int> p3(new int(30));
p2 = p3; // p2賦值給p3,p1計數(shù)變?yōu)?,p3計數(shù)變?yōu)?
cout << "p1計數(shù):" << p1.get_count() << endl; // 輸出1
cout << "p3計數(shù):" << p3.get_count() << endl; // 輸出2
return 0;
}3. 關(guān)鍵細(xì)節(jié)(修復(fù)參考回答的問題)
- 線程安全:
- 參考回答未處理多線程,實際
shared_ptr的引用計數(shù)操作必須加鎖; - 每個
shared_ptr對象共享同一個互斥鎖,保證計數(shù)增減的原子性。
- 參考回答未處理多線程,實際
- 賦值運算符重載:
- 參考回答的賦值邏輯錯誤(先加對方計數(shù),再減自己計數(shù)),正確邏輯是“先釋放自己的資源,再共享對方的資源”;
- 必須處理自賦值(
p = p),否則會導(dǎo)致計數(shù)錯誤。
- 異常安全:
- 構(gòu)造函數(shù)中若
use_count分配失敗,需釋放ptr避免內(nèi)存泄漏; - 解引用/訪問成員時檢查空指針,避免野指針訪問。
- 構(gòu)造函數(shù)中若
4. shared_ptr 核心特性
- 共享所有權(quán):多個
shared_ptr可指向同一資源; - 自動釋放:最后一個指向資源的
shared_ptr析構(gòu)時,釋放底層內(nèi)存; - 線程安全:
- 引用計數(shù)的增減是原子操作(多線程安全);
- 但
shared_ptr的讀寫操作(如p = q)需手動加鎖(非線程安全)。
二、unique_ptr 實現(xiàn)詳解
unique_ptr的核心是獨占所有權(quán):同一時間只有一個unique_ptr能指向某個資源,禁止拷貝,僅支持移動(C++11)。
1. 核心設(shè)計思路
| 核心特性 | 實現(xiàn)方式 |
|---|---|
| 獨占所有權(quán) | 禁用拷貝構(gòu)造/賦值運算符 |
| 移動語義 | 實現(xiàn)移動構(gòu)造/賦值,轉(zhuǎn)移資源所有權(quán) |
| 自動釋放 | 析構(gòu)函數(shù)直接釋放底層資源(無需計數(shù)) |
2. 完整實現(xiàn)
#include <iostream>
#include <utility> // 引入move
using namespace std;
template <typename T>
class UniquePtr {
private:
T* ptr; // 獨占的底層資源指針
public:
// 1. 構(gòu)造函數(shù):接收原始指針
explicit UniquePtr(T* p = nullptr) : ptr(p) {}
// 2. 禁用拷貝構(gòu)造(獨占所有權(quán),禁止拷貝)
UniquePtr(const UniquePtr<T>&) = delete;
// 3. 禁用賦值運算符
UniquePtr<T>& operator=(const UniquePtr<T>&) = delete;
// 4. 移動構(gòu)造函數(shù):轉(zhuǎn)移資源所有權(quán)
UniquePtr(UniquePtr<T>&& other) noexcept {
ptr = other.ptr;
other.ptr = nullptr; // 源對象置空,避免重復(fù)釋放
}
// 5. 移動賦值運算符:轉(zhuǎn)移資源所有權(quán)
UniquePtr<T>& operator=(UniquePtr<T>&& other) noexcept {
if (this == &other) return *this;
// 釋放當(dāng)前資源
delete ptr;
// 轉(zhuǎn)移所有權(quán)
ptr = other.ptr;
other.ptr = nullptr;
return *this;
}
// 6. 析構(gòu)函數(shù):直接釋放資源(無計數(shù),獨占所以直接刪)
~UniquePtr() {
delete ptr;
ptr = nullptr;
}
// 7. 重載解引用運算符
T& operator*() const {
if (ptr == nullptr) throw runtime_error("解引用空指針");
return *ptr;
}
// 8. 重載->運算符
T* operator->() const {
if (ptr == nullptr) throw runtime_error("訪問空指針成員");
return ptr;
}
// 9. 釋放資源(手動放棄所有權(quán))
T* release() {
T* temp = ptr;
ptr = nullptr;
return temp;
}
// 10. 重置資源
void reset(T* p = nullptr) {
delete ptr;
ptr = p;
}
// 11. 獲取原始指針
T* get() const {
return ptr;
}
};
// 測試代碼
int main() {
UniquePtr<int> p1(new int(10));
cout << "*p1 = " << *p1 << endl; // 輸出10
// UniquePtr<int> p2 = p1; // 編譯錯誤:禁用拷貝構(gòu)造
UniquePtr<int> p2 = move(p1); // 移動構(gòu)造,p1置空
// cout << *p1 << endl; // 崩潰:p1已空
cout << "*p2 = " << *p2 << endl; // 輸出10
p2.reset(new int(20)); // 重置資源
cout << "*p2 = " << *p2 << endl; // 輸出20
return 0;
}
3. unique_ptr 核心特性
- 獨占性:禁止拷貝,僅能通過
std::move轉(zhuǎn)移所有權(quán); - 輕量級:無引用計數(shù),內(nèi)存開銷僅等于原始指針;
- 高效:析構(gòu)時直接釋放資源,無計數(shù)操作開銷;
- 支持?jǐn)?shù)組:
unique_ptr<int[]>會自動調(diào)用delete[]釋放數(shù)組。
三、weak_ptr 實現(xiàn)詳解
weak_ptr是為解決shared_ptr的循環(huán)引用問題而生的“弱引用”指針:
- 不擁有資源所有權(quán),僅能觀察
shared_ptr管理的資源; - 不增加引用計數(shù),不會阻止資源釋放;
- 需通過
lock()轉(zhuǎn)換為shared_ptr后才能訪問資源。
1. 核心設(shè)計思路
| 核心成員 | 作用 |
|---|---|
| T* ptr | 指向底層資源的指針(僅觀察,不擁有) |
| int* use_count | 共享shared_ptr的引用計數(shù)(僅讀取,不修改) |
| int* weak_count | 弱引用計數(shù)(記錄weak_ptr的數(shù)量) |
| mutex* mtx | 共享互斥鎖 |
2. 完整實現(xiàn)(依賴shared_ptr)
#include <iostream>
#include <mutex>
using namespace std;
// 先聲明SharedPtr,供WeakPtr使用
template <typename T> class SharedPtr;
template <typename T>
class WeakPtr {
private:
T* ptr; // 底層資源指針(僅觀察)
int* use_count; // 共享_ptr的強(qiáng)引用計數(shù)
int* weak_count; // 弱引用計數(shù)
mutex* mtx; // 共享鎖
// 私有輔助函數(shù):釋放弱引用
void release_weak() {
lock_guard<mutex> lock(*mtx);
if (--(*weak_count) == 0) { // 弱引用計數(shù)為0時,釋放計數(shù)內(nèi)存
delete use_count;
delete weak_count;
delete mtx;
use_count = nullptr;
weak_count = nullptr;
mtx = nullptr;
}
}
public:
// 1. 構(gòu)造函數(shù):默認(rèn)構(gòu)造
WeakPtr() : ptr(nullptr), use_count(nullptr), weak_count(nullptr), mtx(nullptr) {}
// 2. 從shared_ptr構(gòu)造
WeakPtr(const SharedPtr<T>& sp) {
ptr = sp.get();
use_count = sp.use_count_ptr(); // 需要SharedPtr暴露use_count指針(友元)
weak_count = sp.weak_count_ptr();
mtx = sp.get_mutex();
lock_guard<mutex> lock(*mtx);
++(*weak_count); // 弱引用計數(shù)+1
}
// 3. 拷貝構(gòu)造
WeakPtr(const WeakPtr<T>& wp) {
ptr = wp.ptr;
use_count = wp.use_count;
weak_count = wp.weak_count;
mtx = wp.mtx;
lock_guard<mutex> lock(*mtx);
++(*weak_count);
}
// 4. 賦值運算符
WeakPtr<T>& operator=(const WeakPtr<T>& wp) {
if (this == &wp) return *this;
if (weak_count != nullptr) release_weak(); // 釋放當(dāng)前弱引用
ptr = wp.ptr;
use_count = wp.use_count;
weak_count = wp.weak_count;
mtx = wp.mtx;
lock_guard<mutex> lock(*mtx);
++(*weak_count);
return *this;
}
// 5. 析構(gòu)函數(shù):弱引用計數(shù)-1
~WeakPtr() {
if (weak_count != nullptr) {
release_weak();
}
}
// 6. 核心方法:lock()轉(zhuǎn)換為shared_ptr
SharedPtr<T> lock() const {
lock_guard<mutex> lock(*mtx);
if (*use_count > 0) { // 強(qiáng)引用計數(shù)>0,資源未釋放
return SharedPtr<T>(ptr, use_count, weak_count, mtx); // 自定義SharedPtr構(gòu)造函數(shù)
}
return SharedPtr<T>(); // 資源已釋放,返回空shared_ptr
}
// 7. 檢查資源是否有效(未被釋放)
bool expired() const {
lock_guard<mutex> lock(*mtx);
return *use_count == 0;
}
// 8. 獲取強(qiáng)引用計數(shù)
int use_count() const {
lock_guard<mutex> lock(*mtx);
return *use_count;
}
// 禁用移動構(gòu)造/賦值(簡化版)
WeakPtr(WeakPtr<T>&&) = delete;
WeakPtr<T>& operator=(WeakPtr<T>&&) = delete;
// 友元聲明:讓SharedPtr訪問WeakPtr的私有成員
friend class SharedPtr<T>;
};
// 補(bǔ)充SharedPtr的擴(kuò)展(支持WeakPtr)
template <typename T>
class SharedPtr {
private:
T* ptr;
int* use_count;
int* weak_count; // 新增弱引用計數(shù)
mutex* mtx;
void release() {
lock_guard<mutex> lock(*mtx);
if (--(*use_count) == 0) {
delete ptr;
ptr = nullptr;
}
// 弱引用計數(shù)處理移交給WeakPtr
}
// 供WeakPtr::lock()調(diào)用的私有構(gòu)造函數(shù)
SharedPtr(T* p, int* uc, int* wc, mutex* m) : ptr(p), use_count(uc), weak_count(wc), mtx(m) {
lock_guard<mutex> lock(*mtx);
++(*use_count);
}
public:
// 原有構(gòu)造函數(shù)擴(kuò)展弱引用計數(shù)
SharedPtr(T* p = nullptr) : ptr(p) {
try {
use_count = new int(1);
weak_count = new int(0); // 初始弱引用計數(shù)為0
mtx = new mutex();
} catch (...) {
delete ptr;
ptr = nullptr;
throw;
}
}
// 暴露給WeakPtr的接口
int* use_count_ptr() const { return use_count; }
int* weak_count_ptr() const { return weak_count; }
mutex* get_mutex() const { return mtx; }
// 其余方法(拷貝構(gòu)造、賦值、析構(gòu)等)需適配weak_count,此處省略...
T* get() const { return ptr; }
};3. weak_ptr 核心特性
- 弱引用:不增加強(qiáng)引用計數(shù),僅觀察資源;
- 解決循環(huán)引用:如鏈表節(jié)點互相持有
shared_ptr會導(dǎo)致計數(shù)無法歸零,改用weak_ptr即可; - 安全訪問:通過
lock()獲取shared_ptr后才能訪問資源,避免訪問已釋放的資源; - expired():檢查資源是否已被釋放,防止野指針。
四、三種智能指針核心對比
| 特性 | shared_ptr | unique_ptr | weak_ptr |
|---|---|---|---|
| 所有權(quán) | 共享 | 獨占 | 無(僅觀察) |
| 引用計數(shù) | 強(qiáng)引用計數(shù)(控制釋放) | 無 | 弱引用計數(shù)(僅記錄) |
| 拷貝/移動 | 支持拷貝,移動 | 禁用拷貝,支持移動 | 支持拷貝,禁用移動 |
| 內(nèi)存開銷 | 2個指針(資源+計數(shù))+鎖 | 1個指針(僅資源) | 2個指針(資源+計數(shù))+鎖 |
| 核心場景 | 多對象共享資源 | 單對象獨占資源 | 解決shared_ptr循環(huán)引用 |
| 訪問方式 | 直接解引用 | 直接解引用 | 先lock()轉(zhuǎn)為shared_ptr |
五、總結(jié)(核心要點回顧)
- shared_ptr:
- 核心是引用計數(shù),多線程下需加鎖保證計數(shù)原子性;
- 拷貝/賦值時增加計數(shù),析構(gòu)時減少計數(shù),計數(shù)為0釋放資源;
- 缺點:有計數(shù)開銷,易產(chǎn)生循環(huán)引用(需weak_ptr解決)。
- unique_ptr:
- 獨占所有權(quán),禁用拷貝,僅支持移動;
- 輕量級、高效,無計數(shù)開銷,優(yōu)先用于單所有權(quán)場景;
- 支持?jǐn)?shù)組類型,自動適配delete/delete[]。
- weak_ptr:
- 弱引用,不影響資源釋放,專門解決shared_ptr循環(huán)引用;
- 需通過lock()轉(zhuǎn)為shared_ptr才能訪問資源,保證訪問安全;
- 核心方法:lock()(獲取shared_ptr)、expired()(檢查資源有效性)。
智能指針的實現(xiàn)核心是RAII:將資源生命周期綁定到智能指針對象的生命周期,對象析構(gòu)時自動釋放資源,從根本上避免內(nèi)存泄漏。實際開發(fā)中優(yōu)先使用標(biāo)準(zhǔn)庫的std::shared_ptr/std::unique_ptr,其實現(xiàn)更完善(支持自定義刪除器、數(shù)組、線程安全等)。
到此這篇關(guān)于C++四個智能指針的使用小結(jié)的文章就介紹到這了,更多相關(guān)C++ 智能指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

