目前為止我們學過靜態記憶體和棧記憶體,分配在其中的物件由編譯器自動建立和銷毀,
靜態記憶體:用來儲存區域性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,接受乙個動態物件指標,銷毀該物件並釋放與之關聯的記憶體。動態記憶體在使用時很容易出問題,有時會忘記釋放記憶體,造成記憶體洩露,有時在尚有指標...