為瞭解決C++記憶體泄漏的問題,C++11引入了智能指針(Smart Pointer)。 智能指針的原理是,接受一個申請好的記憶體地址,構造一個保存在棧上的智能指針對象,當程式退出棧的作用域範圍後,由於棧上的變數自動被銷毀,智能指針內部保存的記憶體也就被釋放掉了,除非將智能指針保存起來。 C++11提供了 ...
為瞭解決C++記憶體泄漏的問題,C++11引入了智能指針(Smart Pointer)。
智能指針的原理是,接受一個申請好的記憶體地址,構造一個保存在棧上的智能指針對象,當程式退出棧的作用域範圍後,由於棧上的變數自動被銷毀,智能指針內部保存的記憶體也就被釋放掉了,除非將智能指針保存起來。
C++11提供了三種智能指針:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用時需添加頭文件<memory>。
shared_ptr使用引用計數,每一個shared_ptr的拷貝都指向相同的記憶體。每使用他一次,內部的引用技術加1,每析構一次,內部的引用計數減1,減為0時,刪除所指向的堆記憶體。
- shared_ptr的基本用法
- 初始化
可以通過構造函數、std::make_shared<T>輔助函數和reset方法來初始化shared_ptr:
std::shared_ptr<int> p(new int(1)); std::shared_ptr<int> p2 = p; std::shared_ptr<int> p3 = std::make_shared<int>(5); std::shared_ptr<int> ptr; ptr.reset(new int(1)); if (ptr) { cout << "ptr is not null"; }
註意,不能將一個原始指針直接賦值給一個智能指針,如下所示,原因是一個是類,一個是指針。
std::shared_ptr<int> p4 = new int(1);// error
當智能指針中有值得時候,調用reset會使引用計數減1.
- 獲取原始指針
std::shared_ptr<int> p4(new int(5)); int *pInt = p4.get();
- 指定刪除器
智能指針可以指定刪除器,當智能指針的引用計數為0時,自動調用指定的刪除器來釋放記憶體。設置指定刪除器的一個原因是std::shared_ptr預設刪除器不支持數組對象,這一點需要註意。
2. 使用shared_ptr需要註意的問題
但凡一些高級的用法,使用時都有不少陷阱。
- 不要用一個原始指針初始化多個shared_ptr,原因在於,會造成二次銷毀,如下所示:
int *p5 = new int; std::shared_ptr<int> p6(p5); std::shared_ptr<int> p7(p5);// logic error
- 不要在函數實參中創建shared_ptr。因為C++的函數參數的計算順序在不同的編譯器下是不同的。正確的做法是先創建好,然後再傳入。
function(shared_ptr<int>(new int), g());
- 禁止通過shared_from_this()返回this指針,這樣做可能也會造成二次析構。
- 避免迴圈引用。智能指針最大的一個陷阱是迴圈引用,迴圈引用會導致記憶體泄漏。解決方法是AStruct或BStruct改為weak_ptr。
struct AStruct; struct BStruct; struct AStruct { std::shared_ptr<BStruct> bPtr; ~AStruct() { cout << "AStruct is deleted!"<<endl; } }; struct BStruct { std::shared_ptr<AStruct> APtr; ~BStruct() { cout << "BStruct is deleted!" << endl; } }; void TestLoopReference() { std::shared_ptr<AStruct> ap(new AStruct); std::shared_ptr<BStruct> bp(new BStruct); ap->bPtr = bp; bp->APtr = ap; }