C++實(shí)現(xiàn)shared_ptr共享指針的示例代碼
shared_ptr 圖解

一、什么是智能指針?
智能指針 = 自動(dòng)管理內(nèi)存的指針
// 傳統(tǒng)指針的痛點(diǎn) int* p = new int(10); // ... 一堆代碼 delete p; // 萬一忘了寫??jī)?nèi)存泄漏! // 智能指針的優(yōu)雅 #include <memory> shared_ptr<int> sp(new int(10)); // 不用寫 delete!自動(dòng)釋放!
二、shared_ptr 核心特性
| 特性 | 說明 |
|---|---|
| 共享所有權(quán) | 多個(gè)指針可指向同一對(duì)象 |
| 引用計(jì)數(shù) | 記錄有多少指針在共享 |
| 自動(dòng)釋放 | 最后一個(gè)指針銷毀時(shí),自動(dòng)刪除對(duì)象 |
三、創(chuàng)建 shared_ptr 的三種方式
1. 直接 new(不推薦)
shared_ptr<int> sp1(new int(100)); // 單個(gè)int shared_ptr<int[]> sp2(new int[10]); // int數(shù)組(C++17)
2. make_shared(? 推薦)
auto sp3 = make_shared<int>(100); // 單個(gè)int,值100
auto sp4 = make_shared<string>("hello"); // string對(duì)象
auto sp5 = make_shared<vector<int>>(); // vector容器
3. 拷貝構(gòu)造
auto sp6 = sp3; // sp6 和 sp3 指向同一對(duì)象
四、引用計(jì)數(shù):核心機(jī)制
auto sp = make_shared<int>(10);
cout << sp.use_count(); // 輸出:1(只有sp自己)
auto sp2 = sp; // 復(fù)制
cout << sp.use_count(); // 輸出:2(sp和sp2共享)
cout << sp2.use_count(); // 輸出:2
{
auto sp3 = sp; // 又復(fù)制一個(gè)
cout << sp.use_count(); // 輸出:3
} // sp3 銷毀,計(jì)數(shù)-1
cout << sp.use_count(); // 輸出:2
sp2.reset(); // sp2 放棄指向
cout << sp.use_count(); // 輸出:1
sp.reset(); // 最后一個(gè)也放棄
// 此時(shí)計(jì)數(shù)為0,對(duì)象被自動(dòng)刪除
計(jì)數(shù)變化圖解
開始:sp ──→ [數(shù)據(jù):10] 計(jì)數(shù)=1
sp2復(fù)制:sp ──→ [數(shù)據(jù):10] ←── sp2 計(jì)數(shù)=2
sp3復(fù)制:sp ──→ [數(shù)據(jù):10] ←── sp2 計(jì)數(shù)=3
↑
sp3
sp3銷毀:sp ──→ [數(shù)據(jù):10] ←── sp2 計(jì)數(shù)=2
sp2.reset:sp ──→ [數(shù)據(jù):10] 計(jì)數(shù)=1
sp.reset:對(duì)象被刪除
五、常用操作詳解
1. 解引用和成員訪問
auto sp = make_shared<int>(10);
*sp = 20; // 修改值
cout << *sp; // 讀取值
auto spStr = make_shared<string>("hello");
cout << spStr->size(); // 調(diào)用成員函數(shù)
(*spStr)[0] = 'H'; // 修改字符
2. 獲取原始指針
auto sp = make_shared<int>(10); int* raw = sp.get(); // 獲取原始指針 // ?? 警告:raw只是查看,不能刪除! // delete raw; // 千萬不要! // shared_ptr<int> sp2(raw); // 千萬不要!
3. 重置指針
auto sp = make_shared<int>(10); sp.reset(); // 放棄指向,計(jì)數(shù)-1 // 也可以重置并指向新對(duì)象 sp.reset(new int(20)); // 指向新int,原對(duì)象計(jì)數(shù)-1
4. 檢查是否為空
auto sp = make_shared<int>(10);
if (sp) { // ? 簡(jiǎn)潔寫法
cout << "指針不為空";
}
if (sp.get() != nullptr) { // ?? 繁瑣寫法
cout << "指針不為空";
}
六、自定義刪除器
在需要特殊清理時(shí)使用:
// 方式1:普通函數(shù)
void DeleteInt(int* p) {
cout << "自定義刪除函數(shù)" << endl;
delete p;
}
shared_ptr<int> sp1(new int(10), DeleteInt);
// 方式2:Lambda表達(dá)式(推薦)
shared_ptr<int> sp2(new int(10), [](int* p) {
cout << "Lambda刪除" << endl;
delete p;
});
// 實(shí)際應(yīng)用:管理文件句柄
shared_ptr<FILE> spFile(fopen("test.txt", "w"),
[](FILE* f) {
fclose(f);
cout << "文件已關(guān)閉" << endl;
});
七、數(shù)組支持
// C++17 開始支持?jǐn)?shù)組 shared_ptr<int[]> spArr(new int[100]); // ? spArr[0] = 10; // 數(shù)組用 [] 訪問 // 推薦寫法 auto spArr2 = make_shared<int[]>(100); // C++20
八、指向成員的特殊用法
struct Person {
string name;
int age;
double score;
};
auto p = make_shared<Person>();
// 指向?qū)ο蟮哪硞€(gè)成員,但共享整個(gè)對(duì)象的生命周期
shared_ptr<string> spName(p, &p->name);
shared_ptr<int> spAge(p, &p->age);
cout << p.use_count(); // 輸出:3(三個(gè)指針共享整個(gè)Person)
// 即使 spName、spAge 只指向成員,它們?nèi)匀豢刂普麄€(gè)對(duì)象的生命周期
九、常見錯(cuò)誤(一定要記?。。?/h2>
? 錯(cuò)誤1:手動(dòng)刪除 get() 返回的指針
auto sp = make_shared<int>(10); delete sp.get(); // 災(zāi)難!會(huì)重復(fù)刪除導(dǎo)致崩潰
? 錯(cuò)誤2:用原始指針創(chuàng)建多個(gè) shared_ptr
int* p = new int(10); shared_ptr<int> sp1(p); shared_ptr<int> sp2(p); // 災(zāi)難!兩個(gè)獨(dú)立管理同一內(nèi)存 // 程序結(jié)束時(shí)兩次 delete,崩潰!
? 錯(cuò)誤3:循環(huán)引用(高級(jí)話題)
struct Node {
shared_ptr<Node> next;
};
auto a = make_shared<Node>();
auto b = make_shared<Node>();
a->next = b;
b->next = a; // 互相引用,都無法釋放!
// 解決方案:用 weak_ptr
? 錯(cuò)誤4:忘記數(shù)組語法
shared_ptr<int> sp(new int[10]); // 錯(cuò)誤!會(huì)調(diào)用 delete 不是 delete[] shared_ptr<int[]> sp(new int[10]); // 正確!
十、最佳實(shí)踐總結(jié)
? 推薦這樣做
// 1. 優(yōu)先用 make_shared
auto sp = make_shared<int>(10);
// 2. 用 auto 簡(jiǎn)化代碼
auto spVec = make_shared<vector<int>>();
// 3. 用 if(sp) 檢查空指針
if (sp) { /* 使用 */ }
// 4. 需要特殊清理時(shí)用 Lambda
auto spFile = shared_ptr<FILE>(fopen("a.txt", "r"),
[](FILE* f){ fclose(f); });
? 避免這樣做
// 1. 濫用 get() int* raw = sp.get(); // 除非必要 // 2. 手動(dòng)管理引用計(jì)數(shù) // 讓系統(tǒng)自動(dòng)處理就好 // 3. 混用原始指針和智能指針
十一、一句話記憶
shared_ptr 就像合租室友:有人搬進(jìn)來計(jì)數(shù)+1,有人搬走計(jì)數(shù)-1,最后一個(gè)離開時(shí)負(fù)責(zé)打掃房間(刪除對(duì)象)。你只需要安心住,不用操心打掃的事!
到此這篇關(guān)于C++實(shí)現(xiàn)shared_ptr共享指針的示例代碼的文章就介紹到這了,更多相關(guān)C++ shared_ptr共享指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中靜態(tài)成員函數(shù)訪問非靜態(tài)成員的實(shí)例
這篇文章主要介紹了C++中靜態(tài)成員函數(shù)訪問非靜態(tài)成員的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-07-07
關(guān)于C/C++中static關(guān)鍵字的作用總結(jié)
以下是對(duì)C/C++中static關(guān)鍵字的作用進(jìn)行了總結(jié)介紹,需要的朋友可以過來參考下2013-09-09
使用UART與PC通信實(shí)現(xiàn)msp430g2553單片機(jī)超聲波測(cè)距示例
這篇文章主要介紹了使用UART與PC通信實(shí)現(xiàn)msp430g2553單片機(jī)超聲波測(cè)距示例,需要的朋友可以參考下2014-05-05

