C 智慧型指標與記憶體洩漏之間的聯絡

2021-09-25 03:46:54 字數 4055 閱讀 6428

在c++中解決記憶體洩漏的有效方法是使用智慧型指標(smart pointer)。智慧型指標和普通指標的用法類似,只是不需要手動釋放記憶體,而是通過智慧型指標自己管理記憶體釋放。

智慧型指標是儲存指向動態分配(堆)物件指標的類,用於生存期控制,能夠確保在離開指標所在作用域時,自動正確的銷毀動態分配的物件,防止記憶體洩漏。它的一種通用

實現技術是使用引用計數,每使用它一次,內部的引用計數加1,每析構一次,內部引用計數減1,減為0時,刪除所指向的堆記憶體。

c++11 提供了3種智慧型指標:std::shared_ptr、std::uniq_ptr、std::weak_ptr,標頭檔案為

一、shared_ptr 共享的智慧型指標:

1:初始化:

通過 建構函式、std::make_shared輔助函式、reset方法來初始化shared_ptr,優先使用make_shared來構造智慧型指標

std::shared_ptrp(new int(1));

std::shared_ptrp2=p;

std::shared_ptrptr;

ptr.reset(new int(1));

對於乙個未初始化的智慧型指標,可以通過reset方法來初始化。

當智慧型指標中有值的時候,呼叫reset會使引用計數減1,

通過過載bool型別操作符來判斷智慧型指標中是否為空

獲取原始指標:當需要獲取原始指標時,可以通過get方法來返回原始指標

std::shared_ptrptr(new int(1));

int *p=ptr.get();

二:刪除shared_ptr共享指標

(1)刪除指標:

(1)指定刪除器:當p的引用計數為0時,自動呼叫刪除器deleteintptr 來釋放物件的記憶體

void deleteintptr(int* p)

std::shared_ptrp(new int,deleteintptr); //當p的引用計數為0了,就銷毀p

(2) lambda表示式也可以    

std::shared_ptrp(new int,(int *p));

(2)刪除陣列指標

(1)shared_ptr管理動態陣列時,需要強制指定刪除器,預設的刪除器不支援陣列刪除指標。

std::shared_ptrp(new int[10],(int *p));

(2)void deleteintptr(int* p)

(3)std::shared_ptrp(new int,deleteintptr); //當p的引用計數為0了,就銷毀p

(4)也可以將std::default_delete 作為刪除器。default_delete的內部是通過呼叫delete來實現功能的:推薦

std::shared_ptrp(new int[10],std::default_delete);

注意:

(1) 不能將乙個原始指標直接賦值給乙個智慧型指標

std::shared_ptrp=new int(1);//編譯報錯,不允許直接賦值

(2) 不要用乙個原始指標初始化多個shared_ptr,例如下面這些事錯誤的

int *ptr=new int;

shared_ptrp1(ptr);

shared_ptrp2(ptr);//logic error

(3) 不要在函式實參中建立shared_ptr

function (shared_ptr(new int),g());//有缺陷

正確的寫法應該是先建立智慧型指標:    shared_ptrp(new int());   f(p,g());

(4) 通過shared_from_this()返回this指標。不要將this指標作為shared_ptr返回出來,因為this指標本質上是乙個裸指標,因此,這樣可能會導致重複析構。

shared_ptrgetself()

正確做法:讓目標類通過派生std::enable_shared_from_this類,然後使用基類的成員函式shared_from_this來返回shared_ptr

class a:public std::enable_shared_from_this

};std::shared_ptrspy(new a);

std::shared_ptrp=spy->getself(); //正確

(5) 要避免迴圈引用。智慧型指標最大的乙個陷阱是迴圈引用,迴圈引用會導致記憶體洩露:

class a

}

解決方式:在類a、類b中生命的shared_ptr指標有乙個為弱引用指標weak_ptr ,即可解決問題

二、unique_ptr 獨佔的智慧型指標

unique_ptr是乙個獨佔型的智慧型指標,它不允許其他智慧型指標共享其內部的指標.

1、初始化  

(1)不允許通過賦值將乙個unique_ptr賦值給另外乙個unique_ptr。

unique_ptrmyptr(new t);

unique_ptrmyotherptr=myptr;//錯誤!! 不能複製

(2)unique_ptr不允許複製,可以通過函式返回給其他的unique_ptr,可以通過std::move來轉移到其他的unique_ptr,之後它就不在擁有原來指標的所有權.

unique_ptrmyptr(new t); //ok

unique_ptrmyotherptr=std::move(myptr);//ok

(3)unique_ptr除了獨占性這個特點之外,還可以指向乙個陣列

std::unique_ptrptr(new int[10]);

ptr[9]=9;//設定最後乙個元素為9

2、刪除指標,指定刪除器

(1)std::unique_ptr指定刪除器的時候需要確定刪除器的型別

std::unique_ptr> ptr(new int(1),[&](int* p));

(2)自定義unique_ptr的刪除器

void deleter(connection *connection)

unique_ptrup(new connection("unique_ptr"), deleter);

另一種使用方法:

class cconnnect

};class deleter

};std::unique_ptrup2(new cconnnect, up1.get_deleter());

三、weak_ptr 弱引用的智慧型指標

弱引用指標weak_ptr是用來監視shared_ptr的,不會使引用計數加1,它不管理shared_ptr內部的指標,主要是為了監視shared_ptr的生命週期,更像是shared_ptr的乙個助手

(1)初始化:

1:通過use_count()方法來獲得當前觀測資源的引用計數.

shared_ptrsp(new int(10));

weak_ptrwp(sp);

cout<

2:通過expired()方法來判斷所觀測的資源是否已被釋放.

shared_ptrsp(new int(10));

weak_ptrwp(sp);

if(wp.expired())

f();

}//輸出:42 gw is expired

4:weak_ptr返回this指標

提到不能直接將this指標返回為shared_ptr,需要通過派生std::enable_shared_from_this類,

並通過其他方法shared_form_this來返回智慧型指標,因為std::enable_shared_from_this類中有乙個weak_ptr,這個weak_ptr用來觀測this智慧型指標,

呼叫shared_from_this()方法時,會呼叫內部這個weak_ptr的lock方法,將所觀測的shared_ptr返回.

5:weak_ptr 解決迴圈引用問題

class a

}

智慧型指標auto ptr 記憶體洩漏解決

在c 11中,已經不使用auto ptr,而用 unique ptr進行替代,不過二者原理都差不多。標頭檔案 memory 智慧型指標 實質上是乙個類,在建立智慧型指標的時候,本質上是在棧上建立了乙個物件,而析構函式總是會在出棧時被呼叫,清理會自動進行。unique ptr auto ptr 通過在...

c 智慧型指標與記憶體管理

c 中當我們需要新分配記憶體的時候需要手動的去呼叫new顯式的分配一塊記憶體,如果我們在任何中new 如函式中申請空間返回 忘記釋放,或者在 函式執行過程中出現異常,沒 有執行釋放語句 了空間,在不需要使用後忘記了呼叫delete這塊位址的話就會造成 記憶體洩露。為了解決這乙個問題引入了智慧型指標。...

c 用智慧型指標幫我們避免記憶體洩漏問題

c 沒有gc機制,處理堆記憶體時就得小心,所以有了智慧型指標這個玩意。智慧型指標可以理解為普通指標的再封裝,智慧型指標的析構函式包含了對於堆記憶體的釋放操作。unique ptr 同一之間只能有乙個智慧型指標指向該物件 shared ptr 可以有多個shared ptr指向某物件 當引用數量為0時...