c 動態記憶體與智慧型指標

2022-03-30 10:26:49 字數 2891 閱讀 7178

目前為止我們學過靜態記憶體和棧記憶體,分配在其中的物件由編譯器自動建立和銷毀,

靜態記憶體:用來儲存區域性static物件、類的static資料成員、以及定義在任何函式體之外的變數。在物件使用之前分配,程式結束時銷毀。

棧記憶體:用來儲存定義在函式內的非static物件。僅在物件定義的程式塊執行時存在,程式塊執行結束時銷毀。

除此之外,每個程式還擁有乙個記憶體池,這部分記憶體被稱為自由空間,程式用堆來儲存動態分配的物件——程式執行時分配的物件。動態物件不再使用時,需要顯式的銷毀它們。程式使用動態記憶體出於以下三種原因之一:

1、new和delete

c++中動態記憶體的管理是通過一對運算子new和delete完成的:new為物件分配記憶體並返回指向該物件型別的指標,delete接受乙個動態物件的指標,銷毀指向的物件並釋放其記憶體。

1.1、new

(1)動態分配記憶體與初始化

預設情況下,動態記憶體分配的物件是預設初始化的,意味著內建內心和組合型別(如指標和陣列)的物件的值將是為定義的,類型別的物件將使用預設建構函式初始化:

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

使用圓括號或花括號來初始化乙個動態分配的物件:

int *p=new int(1024);

vector*pv=new vector;

在類名後面跟一對空括號來動態分配的物件進行值初始化:

int *p=new int();//值初始化為0

string *ps=new string();//值初始化為空字串

對於定義了建構函式的類來說,要求值初始化是沒有意義的,不管採用什麼方式,物件都會通過預設建構函式來初始化。對於內建型別來說,值初始的物件由良好定義的值,而預設初始化的值是未定義的。

(2)動態分配const物件

const int *pc=new const int(1024);

1.2、delete

(1)釋放記憶體

我們傳遞給delete的指標必須是指向動態分配的記憶體,或是乙個空指標。釋放一塊並非new分配的記憶體,或者將相同的指標釋放多次,其行為是未定義的:

int i,*pi=&i,*p2=nullptr;

double *pd=new double(3.14),*pd2=pd;

delete pi;//錯誤,pi指向的是區域性變數,不是動態分配的記憶體

delete p2;//正確

delete pd;//正確

delete pd2;//錯誤,pd2指向的記憶體已經被釋放掉了

(2)釋放const物件

雖然const物件的值不能被改變,但是可以被銷毀:

delete pc;

(3)delete之後重置指標

delete指標之後,指標值就變為無效的了,雖然指向的記憶體被釋放了,但指標還在,很多機器上指標仍然儲存著原來的動態記憶體的位址。delete之後的指標被稱為空懸指標。為了消除指標與動態記憶體的關聯,可以在delete之後將nullptr賦予指標,但這種方法只對這個指標有效,對多個指標指向相同記憶體的情況下還是作用有限:

int *p=new int(1024);

int *q=p;//p和q指向同一塊動態記憶體

delete p;//p不再繫結任何物件,但是q變成了空懸指標

2、記憶體洩漏

記憶體洩漏:動態分配的記憶體忘記釋放產生記憶體洩漏。

非法記憶體:尚有指標引用了記憶體的情況下釋放了了它,產生引用非法記憶體的指標。

(1)函式呼叫返回動態記憶體指標

在呼叫返回指向動態記憶體的指標時,呼叫者需要記得釋放記憶體:

int * fun(){

return new int(1024);//呼叫者負責釋放此記憶體

(2)函式體內申請動態記憶體

在函式體內申請的動態記憶體要注意釋放:

void fun(){

int *p=new int(1024);

p是指向這塊記憶體的唯一指標,一旦函式返回,程式就沒有辦法釋放這塊記憶體了。

3、智慧型指標

為了更容易地使用動態記憶體,新的標準庫提供了兩種智慧型指標shared_ptr和unique_ptr來管理動態物件,可以自動釋放物件記憶體,定義在memory標頭檔案中。

3.1、shared_ptr

(1)建立指標

類似vector,智慧型指標也是模板,必須提供指標可以指向的型別<>:

shared_ptrps;

shared_ptr> pv;

預設初始化的智慧型指標中儲存的是乙個空指標。一般指標預設初始化是未定義的。

(2)分配記憶體——make_shared函式

make_shared函式在動態記憶體中分配乙個物件並初始化它,返回指向物件的shared_ptr,同樣需要指定想要建立物件的型別<>:

shared_ptrpi=make_shared();//如果不傳遞任何引數,物件執行值初始化

shared_ptrpi=make_shared(1034);//直接初始化

通常使用auto來儲存make_shared的結果,這種方式更為簡單:

auto p=make_shared>();

(3)引用計數

每個shared_ptr都有乙個關聯的計數器來記錄有多少個shared_ptr指向相同的物件,通常稱其為引用計數。

無論何時我們拷貝乙個shared_ptr,計數器都會遞增:

計數器遞減:

(4)自動銷毀物件

當物件的最後乙個shared_ptr被銷毀時,它會自動銷毀指向的物件,它是通過析構函式完成 的,析構函式會遞減它所指向物件的引用計數,當引用計數變為0時,析構函式會銷毀物件,並釋放它占用的記憶體。同理,當動態物件不再被使用時,shared_ptr會自動釋放動態物件。

C 動態記憶體與智慧型指標

qq 1841545843 郵箱 jiaxx903 163.com 靜態記憶體用來儲存區域性 static 物件 類的 static 資料成員,以及定義在任何函式之外的變數。棧記憶體用來儲存定義在函式之內的 static 物件。除了棧記憶體和靜態記憶體外,每個程式還擁有乙個記憶體池,這部分稱之為 堆...

動態記憶體與智慧型指標

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

動態記憶體與智慧型指標

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