26 智慧型指標和動態記憶體

2021-08-28 23:14:58 字數 3952 閱讀 9845

在c++中,動態記憶體的管理是通過一對運算子來完成的new在動態記憶體中為物件分配空間並返回乙個指向該記憶體物件的指標。

delete,接受乙個動態物件的指標,銷毀該物件,並釋放與之關聯的記憶體!

為什麼要用智慧型指標?

動態記憶體的使用很容易出現問題,因為確保在正確的時間釋放記憶體是極其困難的。有時候我們會忘記釋放記憶體這就會導致產生記憶體洩漏;為了更容易同時也更安全的使用動態記憶體,新的標準庫提供了兩種智慧型指標型別來管理動態物件!

智慧型指標分哪幾種?

shared_ptr : 允許多個指標指向乙個物件

unique_ptr : 乙個指標獨佔乙個物件

make_shared函式:在動態記憶體中建立乙個物件並初始化它,返回指向該物件的乙個shared_ptr指標。

#includeshared_ptrp2 = make_shared(42);
引用計數的問題:當用乙個shared_ptr去初始化另乙個shared_ptr,或者將它作為引數傳遞給乙個函式,或者作為函式的返回值。這些操作都會增加引用計數!

一旦乙個shared_ptr的計數器變為0,它就會自動釋放自己所管理的物件!

舉個栗子:

shared_pt***ctory(t arg)

void use_factory(t arg)

有上面的**我們知道,當use_factory執行結束的時候,p就會被銷毀,由於p所指向的物件只有乙個引用,那麼當p被銷毀的時候,對應的物件的記憶體就會被釋放!

再來看,我們將**稍微變動一下

shared_pt***ctory(t arg)

shared_ptruse_factory(t arg)

當use_factory執行結束的時候,p就會被銷毀,但是返回了p的副本,也就是增加了記憶體物件的引用計數,那麼記憶體物件就不會被釋放!

new在動態記憶體中為物件分配空間並返回乙個指向該記憶體物件的指標,該指標是內建型別指標,我們在使用完記憶體物件的時候一定要記得顯式地手動delete記憶體。

舉個栗子:

foo* factory(t arg)

void use_factory(t arg)

有上面的**我們知道,當use_factory執行結束的時候,p就會被銷毀,但是它所指向的記憶體沒有被釋放!這就會導致所謂的記憶體洩露!因此我們需要顯示的釋放記憶體!或者返回乙個指標副本指向這個記憶體物件!

foo* factory(t arg)

void use_factory(t arg)

//或者

void use_factory(t arg)

考慮到動態記憶體的管理很容易出現記憶體洩露或者把相同的指標delete多次。我們將new和shared_ptr結合使用!

但是new返回的是內建指標,因此只能夠在對shared_ptr進行初始化的時候,直接使用值初始化!而不能夠隱式轉換!

shared_ptrp(new int(42));
因此:乙個用來初始化智慧型指標的普通指標必須是指向動態記憶體的!

那有沒有相反的機制?即從智慧型指標退化到普通指標?

答案當然是有!智慧型指標型別定義了乙個get()函式,返回乙個內建指標,它指向智慧型指標所指向的物件!記住!!!不能夠delete這個內建指標!因為智慧型指標還在引用這個記憶體物件!

當將乙個內建指標所指向的記憶體繫結到乙個智慧型指標上的時候,我們就不應該再使用內建指標去訪問這塊記憶體了。當我們需要向乙個不能使用智慧型指標的**傳遞乙個內建指標,就可以使用get函式。

get是用來將指標的訪問許可權交給**,只有在確認**不會delete這個返回的內建指標的時候,才能夠使用get!而且不能使用get返回的指標去初始化另乙個智慧型指標!

智慧型指標和異常

當我們使用某個**塊中使用了智慧型指標,且在**塊執行完成之前丟擲了異常,且沒有進行捕獲處理,在程式退出之後,智慧型指標所指向的記憶體是可以被銷毀**的!但是如果是內建的指標的話,那麼在delete之前丟擲異常導致程式退出的話,那麼這部分記憶體無法被**了,也即產生了記憶體洩露。

其它的shared_ptr的操作:

1)reset()

shared_ptrp = make_shared(42);

p.reset(new int(42)); //p指向新的物件

2)unique()  用來判斷是否只有自身這乙個智慧型指標指向這個記憶體物件!

if(!p.unique())

p.reset(new string(*p)); //拷貝物件,指向新的拷貝物件!

*p += 「hello」; //如果是唯一的,改變物件的值

unique_ptr 乙個指標獨佔乙個物件!和new結合使用的時候,初始化必須要直接初始化!

由於unique_ptr獨享指向的記憶體物件!因此unique_ptr不支援普通的拷貝或賦值操作!

我們使用 release()和reset()將指標的所有權轉移到另乙個unique_ptr上。

unique_ptrp1(new int(1024));

unique_ptrp2(p1.release())

unique_ptrp3(new int(2048));

p2.reset(p3.release());

release()返回的內建指標常用來初始化另外乙個智慧型指標或者給另外乙個智慧型指標賦值!如果我們不用乙個智慧型指標來儲存返回的指標,我們就要記得手動delete這個指標!

還可以向unique_ptr傳遞刪除器

unique_ptrp (new objt , fcn);
weak_ptr:是一種不控制所指向物件的智慧型指標,它指向乙個由shared_ptr管理的物件。將乙個weak_ptr繫結到乙個shared_ptr不會改變shared_ptr的引用計數。一旦最後乙個shared_ptr被銷毀,那麼物件就會被釋放。即使有weak_ptr指向物件,物件也會被釋放!

在建立乙個weak_ptr的時候,要用乙個shared_ptr來初始化!

不能使用weak_ptr直接訪問物件,要使用lock()函式。此函式檢查weak_ptr指向的記憶體物件是否存在!如果存在返回乙個shared_ptr。

shared_ptrp = make_shared(1024);

weak_ptrwp(p);

if(sharednp = wp.lock()){} //存在則返回乙個shared_ptr

weak_ptr能夠解決空懸指標問題和迴圈引用的問題

動態記憶體和智慧型指標

c primer 第五版 p399 全域性物件在程式啟動時分配,程式結束時銷毀。區域性變數,進去其定義所在的程式塊時被建立沒在離開塊時銷毀。區域性static物件在第一次使用前分配,在程式結束時銷毀。動態分配的物件的生存期與它們在 建立是無關的,只有當顯式地被釋放時,物件才會銷毀。為安全使用動態物件...

動態記憶體與智慧型指標

動態記憶體與智慧型指標 靜態記憶體用來儲存區域性static物件 類static資料成員以及定義在任何函式之外的變數 全域性變數 棧記憶體用來儲存定義在函式內的非static物件。分配在靜態或棧記憶體中的物件由編譯器自動建立和銷毀。對於棧物件,僅在其定義的程式塊執行時才存在 static物件在使用之...

動態記憶體與智慧型指標

在c 中,動態記憶體的管理是通過一對運算子來完成的 new,在動態記憶體中為物件分配空間並返回乙個指向該物件的指標,我們可以選擇對物件進行初始化 delete,接受乙個動態物件指標,銷毀該物件並釋放與之關聯的記憶體。動態記憶體在使用時很容易出問題,有時會忘記釋放記憶體,造成記憶體洩露,有時在尚有指標...