C 智慧型指標的原理與使用

2021-08-22 07:19:41 字數 4872 閱讀 3098

1、智慧型指標的原理及作用 

c++程式中不僅包含靜態記憶體和棧記憶體,還有乙個記憶體池,記憶體池中的記憶體被稱為自由空間或者堆。程式通常使用堆來儲存動態分配的物件(程式執行時分配的物件),當動態物件不再被使用時,**必須顯式的將它們銷毀。動態記憶體的管理是通過運算子new和delete完成的。

new運算子:在動態記憶體中為物件分配一塊空間並返回乙個指向該物件的指標。

int i;

int *p0 = &i;

int *p1 = new int; //指向乙個動態分配的、未初始化的無名物件

int *p2 = new int(2); //*p2初始化值為2

int *p3 = new int[1000]; //申請1000個單位的記憶體空間

delete運算子:指向乙個動態物件的指標,銷毀物件並釋放與其相關聯的記憶體。在delete之後,指標變成了懸空指標(指向一塊曾經儲存資料物件但現在已經無效的記憶體位址)。想要避免懸空指標,需要在delete之後將nullptr賦值給指標變數,這樣就清楚的指出指標不指向任何物件。

delete p0; //error, p0指標不是用new動態申請的

delete p1;

p1 = nullptr;

delete p2;

p2 = nullptr;

delete p3; //在用new申請時用了,所以在delete時也要用

使用new和delete運算子進行動態記憶體的管理雖然可以提高程式的效率,但是也非常容易出問題。

(1)忘記釋放記憶體,造成記憶體洩漏

(2)在尚有指標引用記憶體的情況下就將其釋放,產生引用非法記憶體的指標

(3)程式發生異常後進入catch忘記釋放記憶體以及多次釋放同一塊記憶體,造成記憶體洩漏

為了讓動態記憶體的使用更加安全、簡便,c++引入了智慧型指標的概念。什麼是智慧型指標?智慧型指標是借用raii技術對普通指標進行封裝,其實質是乙個物件,行為表現為乙個指標,也就是智慧型的管理動態記憶體的釋放。那raii技術具體又是什麼呢?raii技術(resource acquisition is initialization),也稱為「資源獲取就是初始化」,是c++語言的一種管理資源、避免洩漏的慣用法。使用類來封裝資源的分配和初始化,在建構函式中完成資源的分配和初始化,在析構函式中完成資源的清理,可以保證正確的初始化和資源釋放。     

2、智慧型指標的分類和使用

c++11版本之後提供的智慧型指標包含在標頭檔案中,分別是auto_ptr、shared_ptr、unique_ptr、weak_ptr。其中auto_ptr已被棄用,所以這裡不再贅述。

2.1  shared_ptr

shared_ptr是一種強引用指標,允許多個指標指向相同的物件,是乙個標準的共享所有權的智慧型指標。每個shared_ptr都會有乙個計數器與之相關聯,通常稱其為引用計數。下面,我們簡單介紹下shared_ptr的用法:

(1)初始化

可以使用建構函式初始化(指定型別,傳入指標即可),也可以使用make_shared函式初始化(最安全的方法,推薦使用)

std::shared_ptrsp; //空shared_ptr,可以指向型別為t的物件

std::shared_ptrsp(new int(5)); //指定型別,傳入指標通過建構函式初始化

std::shared_ptrsp = std::make_shared(5); //使用make_shared函式初始化

//智慧型指標是乙個模板類,不能將乙個原始指標直接賦值給乙個智慧型指標,因為乙個是類,乙個是指標

std::shared_ptrsp = new int(1); //error

//shared_ptr不能直接支援動態陣列,需要顯示指定刪除器

std::shared_ptrsp(new int[10], (int* p)); //指定delete

std::shared_ptrsp(new int[10], std::default_delete()); //指定std::default_delete

(2)拷貝和賦值

當拷貝乙個shared_ptr時,內部的引用計數加1;當給shared_ptr賦值或shared_ptr被銷毀時,內部的引用計數減1;當引用計數減為0時將會自動釋放自己所管理的物件。

std::shared_ptrsp = std::make_shared(5); //sp指向的int物件只有乙個引用者,引用計數為1

std::shared_ptrspcopy(sp); //spcopy是sp的拷貝,此操作會遞增sp指向物件的引用計數

std::shared_ptrsp1 = std::make_shared(6);

sp = sp1; //給sp賦值,使它指向另乙個位址,此操作會遞增sp1指向物件的引用計數,遞減sp原來指向物件的引用計數

(3)自動釋放所管理的物件以及相關聯的記憶體

shared_ptr是通過其析構函式來完成自動釋放的工作。shared_ptr的析構函式會遞減其所指向物件的引用計數,當引用計數變為0時,析構函式就會銷毀物件並釋放其所占用的記憶體。注意:若將shared_ptr存放於乙個容器中,而後只使用其中部分元素,不再需要全部元素時,千萬記得用erase刪除不在需要的那些元素。

(4)和普通指標的混合使用

2.2  unique_ptr

顧名思義,unique_ptr唯一擁有其所指的物件,在同一時刻只能有乙個unique_ptr指向給定物件,因此unique_ptr不支援普通的拷貝和賦值操作。下面,我們簡單介紹下unique_ptr的用法:

(1)初始化

unique_ptr不像shared_ptr一樣擁有make_shared函式來建立乙個shared_ptr例項。因此我們需要將乙個new操作符返回的指標傳遞給unique_ptr的建構函式來完成初始化。unique_ptr提供了對動態陣列的支援,指定刪除器是乙個可選項。

std::unique_ptrup; //空unique_ptr,可以指向型別為t的物件,up會使用delete來釋放它的指標

std::unique_ptrup(new int(5)); //繫結動態物件

std::unique_ptrup(new int[5]); //可選擇是否指定刪除器

(2)拷貝和賦值

unique_ptr沒有copy建構函式,不支援普通的拷貝和賦值操作;但卻提供了一種移動機制來將指標的所有權從乙個unique_ptr轉移給另乙個unique_ptr(使用std::move函式,也可以呼叫release或reset)。

std::move:獲取乙個繫結到左值上的右值引用

u.release:u放棄對指標的控制權,返回指標,並將u置為空

u.reset:釋放u指向的物件

u.reset(q):如果提供了內建指標q,令u指向這個物件,否則將u置為空

std::unique_ptrup(new int(5));

std::unique_ptrupcopy(up); //error,不能拷貝

std::unique_ptrupassign = up; //error,不能賦值

std::unique_ptrupmove = std::move(up); //轉移所有權

std::cout << *up << std::endl; //error,up經過std::move後為空

std::unique_ptrup1(new int(5));

std::unique_ptrup2(up1.release()); //up2被初始化為up1原來儲存的指標,且up1置為空

std::unique_ptrup3(new int(6));

up2.reset(up3.release()); //reset釋放了up2原來指向的記憶體,指向up3原來儲存的指標,且將up3置為空

(3)使用場景

unique_ptr適用範圍比較廣泛,它可返回函式內動態申請資源的所有權;可在容器中儲存指標;支援動態陣列的管理。

std::unique_ptrcloneuniqueptr(int p)

int main()

); up2[0] = 0; //過載了operation

}

2.3  weak_ptr

weak_ptr是一種弱引用指標,它是伴隨shared_ptr而來的,不具有普通指標的行為。它主要是解決了shared_ptr引用計數的問題:在迴圈引用時會導致記憶體洩漏的問題。

(1)初始化

weak_ptr指向乙個由shared_ptr管理的物件,將乙個weak_ptr繫結到乙個shared_ptr不會改變shared_ptr的引用計數。

std::weak_ptrwp; //空weak_ptr,可以指向型別為t的物件

std::weak_ptrwp(new int(5)); //使用weak_ptr物件構造

std::shared_ptrsp = std::make_shared(6);

std::weak_ptrwp(sp); // 使用shared_ptr物件構造

(2)成員函式

wp.use_count():與該wp共享的shared_ptr的數量

wp.expired():如果wp.use_count() == 0,返回true,否則返回false

lock():如果wp.expired()為true,返回乙個空shared_ptr,否則返回乙個指向wp物件的shared_ptr

成員函式的使用如下:

std::shared_ptrsp = std::make_shared(5);

std::weak_ptrwp(sp);

std::cout << wp.use_count() << std::endl;

if(!wp.expired())

C 智慧型指標原理

智慧型指標 smart pointer 是儲存指向動態分配 堆 物件指標的類,用於生存期控制,能夠確保自動正確的銷毀動態分配的物件,防止記憶體洩露。它的一種通用實現技術是使用引用計數 reference count 智慧型指標類將乙個計數器與類指向的物件相關聯,引用計數跟蹤該類有多少個物件共享同一指...

C 智慧型指標原理

1.c 智慧型指標 2.c 智慧型指標簡單剖析 3.智慧型指標 auto ptr 詳解 4.c 智慧型指標詳解 5.請你介紹一下c 的智慧型指標 牛客網 在c 程式裡,使用new關鍵字開闢的記憶體必須被手動delete掉,不然就會導致記憶體的洩漏,但是,當程式非常冗長,你能保證自己每乙個手動開闢的記...

C 智慧型指標及其原理

智慧型指標介紹 智慧型指標 raii 是利用物件的生命週期來管理資源的技術。raii,resource acquisition is initialization 顧名思義,就是在初始化物件的時候獲取資源,在這個物件進行析構時會幫我們釋放資源,這樣做的好處有很多 不需要顯示的釋放資源 可以避免因為沒...