C++ 智能指針
一、智能指針類型概覽
C++ 標準庫提供以下智能指針(需包含頭文件 <memory>
):
- unique_ptr:獨占所有權,不可復制, 可移動
- shared_ptr:共享所有權,用于引用計數
- weak_ptr:觀察 shared_ptr 對象,不增加計數
二、unique_ptr(獨占指針)
核心特性:
- 唯一擁有指向對象的所有權
- 支持移動語義(所有權轉移)
- 離開作用域自動釋放內存
#include <iostream>
#include <memory>void unique_ptr_demo() {// 創建智能指針 (C++14推薦make_unique)std::unique_ptr<int> p1 = std::make_unique<int>(10);// 訪問數據std::cout << *p1 << std::endl; // 輸出:10// 所有權轉移std::unique_ptr<int> p2 = std::move(p1);std::cout << (p1 ? "非空" : "空") << std::endl; // 輸出:空
}int main() {unique_ptr_demo();return 0;
}
三、shared_ptr(共享指針)
核心特性:
- 通過引用計數共享所有權
- 最后一個指針銷毀時釋放內存
- 支持自定義刪除器
#include <iostream>
#include <memory>class Data {
public:Data() { std::cout << "Data構造" << std::endl; }~Data() { std::cout << "Data析構" << std::endl; }
};void shared_ptr_demo() {std::shared_ptr<Data> p1;{ // 內部作用域auto p2 = std::make_shared<Data>();p1 = p2; // 共享所有權std::cout << "引用計數: " << p1.use_count() << std::endl; // 輸出:2}std::cout << "引用計數: " << p1.use_count() << std::endl; // 輸出:1
}int main() {shared_ptr_demo();return 0;
}
share_ptr引起的循環引用的問題。循環引用就是內存泄漏。 因為對象之間相互引用,使得引用計數永遠不會變為 0 ,對象所占用的堆內存一直無法被釋放。隨著程序運行,不斷出現這種循環引用的情況,會導致可用內存越來越少,最終可能使程序崩潰,或者引發系統性能問題。
#include <memory>
#include <iostream>class B;
class A {
public:std::shared_ptr<B> bptr;~A() {std::cout << "~A()" << endl;}
};class B {
public:std::shared_ptr<A> aptr;~B() {std::cout << "~B()" << endl;}
};int main() {std::shared_ptr<A> aa = std::make_shared<A>();std::shared_ptr<B> bb = std::make_shared<B>();aa->bptr = bb;bb->aptr = aa;return 0;
}
四、weak_ptr(弱指針)
weak_ptr 是一種弱引用智能指針,它指向由 shared_ptr 管理的對象,但不增加對象的引用計數
核心特性:
- 不增加引用計數
- 解決 shared_ptr 循環引用問題
- 必須轉換為 shared_ptr 才能訪問數據
#include <iostream>
#include <memory>class Node {
public:std::weak_ptr<Node> partner; // 使用weak_ptr打破循環~Node() { std::cout << "節點銷毀" << std::endl; }
};void weak_ptr_demo() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->partner = node2;node2->partner = node1;if(auto sp = node1->partner.lock()) { std::cout << "有效伙伴節點" << std::endl; }
}int main() {weak_ptr_demo();return 0;
}
五、編譯與運行
-
編譯命令:
g++ -std=c++14 -o smart_ptr_demo smart_ptr_demo.cpp
-
運行結果:
Data構造 引用計數: 2 引用計數: 1 Data析構 節點銷毀 節點銷毀
六、選擇指南
指針類型 | 使用場景 | 性能開銷 |
---|---|---|
unique_ptr | 獨占資源的場景(90%日常使用) | 無 |
shared_ptr | 需要共享所有權的復雜場景 | 有 |
weak_ptr | 解決循環引用或觀察共享資源 | 低 |
最佳實踐:
- 優先使用
make_unique
/make_shared
創建指針 - 避免裸指針與智能指針混用
- 明確所有權關系,能用
unique_ptr
就不用shared_ptr