Serie: C++
cpp
187 righe
· Aggiornato 2026-06-15
smart_pointers.cpp
C++/Part1_基礎入門/Ch06_指標與參考/smart_pointers.cpp
// ============================================================
// Ch06 — 智慧指標(Smart Pointers)
// 現代 C++ 的記憶體管理:RAII、unique_ptr、shared_ptr、weak_ptr
// 編譯:g++ -std=c++17 -Wall -o smart_pointers smart_pointers.cpp
// ============================================================
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// ── 示範用的簡單類別:在建構/解構時印出訊息,方便觀察生命週期 ──
struct Resource {
std::string name;
explicit Resource(std::string n) : name(std::move(n)) {
std::cout << " [建構] Resource(" << name << ")\n";
}
~Resource() {
std::cout << " [解構] ~Resource(" << name << ")\n";
}
void use() const {
std::cout << " 使用中:" << name << "\n";
}
};
// ── 函式原型 ──
void demonstrateRawPointerProblem();
void demonstrateUniquePtr();
void demonstrateUniquePtrOwnership();
void demonstrateSharedPtr();
void demonstrateWeakPtr();
void demonstrateSmartPtrAsParameter();
// 以「擁有權轉移」表達語意:函式接管資源
void takeOwnership(std::unique_ptr<Resource> res) {
std::cout << " takeOwnership 接管了 " << res->name << "\n";
res->use();
// 函式結束,res 離開作用域 → 自動 delete
}
// 以「只是使用、不擁有」表達語意:傳裸指標或參考
void observe(const Resource* res) {
if (res != nullptr) {
std::cout << " observe(不擁有):" << res->name << "\n";
}
}
// 共享擁有權:以值傳遞 shared_ptr(參考計數 +1)
void share(std::shared_ptr<Resource> res) {
std::cout << " share 內參考計數 = " << res.use_count() << "\n";
}
// ── 主程式 ────────────────────────────────────────
int main() {
std::cout << "===== Ch06:智慧指標 =====\n\n";
demonstrateRawPointerProblem();
demonstrateUniquePtr();
demonstrateUniquePtrOwnership();
demonstrateSharedPtr();
demonstrateWeakPtr();
demonstrateSmartPtrAsParameter();
return 0;
}
// ── 1. 裸指標的問題:手動管理容易出錯 ──
void demonstrateRawPointerProblem() {
std::cout << "【1】裸指標的問題\n";
Resource* raw = new Resource("RawPtr");
raw->use();
// 風險:
// - 忘記 delete → 記憶體洩漏(memory leak)
// - 中途 return / 例外 → delete 不會執行
// - delete 兩次 → double free
delete raw; // 必須手動釋放
raw = nullptr; // 避免懸垂指標
std::cout << " 手動 delete 完成(容易遺漏!)\n\n";
}
// ── 2. unique_ptr:獨佔擁有權,零額外開銷 ──
void demonstrateUniquePtr() {
std::cout << "【2】unique_ptr(獨佔擁有權)\n";
// 優先使用 make_unique(C++14),而非 new
std::unique_ptr<Resource> p = std::make_unique<Resource>("Unique");
p->use();
std::cout << " p.get() 位址 = " << p.get() << "\n";
// unique_ptr 不可複製,但可以移動(轉移擁有權)
std::unique_ptr<Resource> q = std::move(p);
std::cout << " std::move 後,p 是否為空? " << (p == nullptr ? "是" : "否") << "\n";
q->use();
// unique_ptr 也能管理陣列
std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
for (int i = 0; i < 5; i++) arr[i] = (i + 1) * 10;
std::cout << " unique_ptr<int[]>:";
for (int i = 0; i < 5; i++) std::cout << arr[i] << " ";
std::cout << "\n";
std::cout << " 離開作用域時自動解構 →\n";
// q 與 arr 在此自動釋放,不需 delete
}
// ── 3. unique_ptr 的擁有權轉移 ──
void demonstrateUniquePtrOwnership() {
std::cout << "\n【3】unique_ptr 擁有權轉移\n";
auto res = std::make_unique<Resource>("Movable");
std::cout << " 將擁有權交給 takeOwnership:\n";
takeOwnership(std::move(res)); // 明確轉移
std::cout << " 回到 main,res 是否為空? " << (res == nullptr ? "是" : "否") << "\n\n";
}
// ── 4. shared_ptr:共享擁有權,參考計數 ──
void demonstrateSharedPtr() {
std::cout << "【4】shared_ptr(共享擁有權)\n";
std::shared_ptr<Resource> a = std::make_shared<Resource>("Shared");
std::cout << " 建立 a,use_count = " << a.use_count() << "\n";
{
std::shared_ptr<Resource> b = a; // 複製 → 計數 +1
std::cout << " 複製為 b,use_count = " << a.use_count() << "\n";
share(a); // 以值傳遞,函式內計數 +1
std::cout << " 函式返回後,use_count = " << a.use_count() << "\n";
} // b 離開作用域 → 計數 -1
std::cout << " b 離開作用域後,use_count = " << a.use_count() << "\n";
std::cout << " 當最後一個 shared_ptr 銷毀時才會解構 →\n\n";
}
// ── 5. weak_ptr:非擁有觀察者,打破循環參考 ──
struct Node {
std::string name;
std::shared_ptr<Node> next; // 擁有下一個節點
std::weak_ptr<Node> prev; // 觀察上一個節點(避免循環參考)
explicit Node(std::string n) : name(std::move(n)) {
std::cout << " [建構] Node(" << name << ")\n";
}
~Node() {
std::cout << " [解構] ~Node(" << name << ")\n";
}
};
void demonstrateWeakPtr() {
std::cout << "【5】weak_ptr(非擁有觀察者 / 打破循環)\n";
auto first = std::make_shared<Node>("First");
auto second = std::make_shared<Node>("Second");
first->next = second; // first 擁有 second
second->prev = first; // 若用 shared_ptr 會形成循環 → 記憶體洩漏!
// 改用 weak_ptr 即可正常釋放
std::cout << " first.use_count = " << first.use_count() << "\n";
std::cout << " second.use_count = " << second.use_count() << "\n";
// 透過 lock() 安全取得 weak_ptr 指向的物件
if (auto p = second->prev.lock()) {
std::cout << " second 的前一個節點是:" << p->name << "\n";
}
std::cout << " 離開作用域,節點正確解構(無洩漏)→\n\n";
}
// ── 6. 以智慧指標表達函式的擁有權語意 ──
void demonstrateSmartPtrAsParameter() {
std::cout << "【6】用參數型別表達擁有權語意\n";
auto res = std::make_unique<Resource>("Param");
// 只是「使用」→ 傳裸指標 / 參考,不轉移擁有權
observe(res.get());
std::cout << " res 仍由 main 擁有,可繼續使用:\n";
res->use();
std::cout << "\n 口訣:\n";
std::cout << " 接管擁有權 → 以值傳 unique_ptr\n";
std::cout << " 共享擁有權 → 以值傳 shared_ptr\n";
std::cout << " 只是使用 → 傳 T* 或 T&(非擁有)\n";
}
Articoli correlati
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Leggi l'articolo →
C++
c
Aggiornato 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Leggi l'articolo →
C++
cpp
Aggiornato 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Leggi l'articolo →