C Primer 第12章 動態記憶體

2022-02-10 04:38:40 字數 2716 閱讀 8131

程式有3中記憶體分配方式,靜態記憶體用來儲存區域性static物件,類static資料成員以及定義在任何函式之外的物件,棧記憶體用來儲存定義在函式內的非static物件。靜態記憶體和棧記憶體中的物件由編譯器建立或銷毀。程式用堆來儲存動態分配的物件,動態物件必須顯示銷毀。

動態記憶體與智慧型指標

用new運算子在動態記憶體區域為物件分配空間並返回指向該物件的位址,delete運算子接受new返回的指標,銷毀指向的物件並釋放記憶體空間。標準庫定義了2種智慧型指標,他們定義在了memory標頭檔案中。

shared_ptr允許多個指標指向同乙個物件,智慧型指標是模板類,因此在建立時需要指定型別。預設初始化的智慧型指標中儲存著乙個空指標。

使用make_shared函式分配動態記憶體並返回指向該物件的shared_ptr,傳遞給make_shared引數必須與型別的某個建構函式匹配,make_shared呼叫對應的建構函式初始化物件。

shared_ptr使用引用計數來保證記憶體的釋放,當引用計數變為0時自動釋放所管理的記憶體,當拷貝、賦值乙個shared_ptr時會增加引用計數,如賦值時或用乙個shared_ptr初始化另乙個或給函式傳遞引數時或作為函式的返回值時。當我們給shared_ptr賦新值時或被銷毀時,shared_ptr原來指向的物件的引用計數減1。當引用計數變為0是釋放所指向的物件。

使用動態記憶體的乙個常見原因是在多個物件之間共享資料。

當使用shared_ptr型別的資料成員時,可以實現在多個物件中共享同乙個資料成員物件。

預設情況下,動態分配的物件是預設初始化的,也可以使用直接初始化方式或傳統的構造方式或大括號括起來的初始化列表方式,也可以使用值初始化方式(類型別名後面跟空括號)。可以通過使用auto來推斷要分配的物件的型別,如auto p=new auto(obj1);p指向與obj1型別相同的物件,並且該物件用obj1初始化。

可以動態分配const物件,但物件必須進行初始化,如果物件為類型別可以使用預設建構函式初始化。

當使用new分配記憶體失敗時,會丟擲std::bad_alloc型別的異常。通過給new傳遞乙個引數可以改變這種預設行為,new(nothrow) int告訴編譯器不要丟擲異常,若記憶體分配失敗時返回空指標。bad_alloc和nothrow都定義在new標頭檔案中。

通過delete釋放由new分配的記憶體,delete也可以釋放乙個const型別的物件。注意delete只能釋放由new分配的物件。

使用new和delete管理動態記憶體存在的3個問題,忘記delete記憶體,使用已經釋放掉的記憶體,同乙個物件被釋放兩次。堅持只使用智慧型指標就可以避免這些問題。

delete記憶體後重置指標值,即賦值為nullptr。

可以使用new返回的指標來初始化shared_ptr指標。預設情況下,智慧型指標只能繫結到使用new分配的動態記憶體上,也可以繫結到其他型別的指標上,但是需要自定義delete運算子。

不要混合使用智慧型指標與普通指標,一旦把普通指標繫結到智慧型指標上就把記憶體的管理責任交給智慧型指標。不要混合使用智慧型指標和普通內建指標。也不要使用get返回的指標初始化另乙個智慧型指標或給內建指標賦值。注意永遠不要用get返回的指標初始化另乙個智慧型指標。

通過使用智慧型指標可以管理需要手動釋放資源的物件,只需要在初始化智慧型指標時傳遞對應的刪除器函式。

不要使用相同的內建指標初始化多個智慧型指標物件。不要delete get返回的指標。不要使用get返回的指標初始化另乙個智慧型指標。如果使用智慧型指標管理的資源不是new分配的記憶體,記得傳遞給它乙個刪除器。

unique_ptr擁有它所指向的物件,某一時刻只能有乙個unique_ptr指向物件。當unique_ptr被銷毀時,它所指向的物件被銷毀。

由於unique_ptr擁有它所指向的物件,因此unique_ptr不支援普通的拷貝和賦值操作,unique_ptr建立時必須繫結到它所擁有的物件。但是可以通過呼叫release或reset把指標的擁有權從乙個unique_ptr轉移到另乙個unique_ptr。

可以拷貝或賦值乙個將要銷毀的unique_ptr,常見的例子是從函式返回乙個unique_ptr物件。

weak_ptr指向乙個由shared_ptr管理的物件,不能通過weak_ptr直接訪問物件,必須通過lock函式,lock函式返回shared_ptr,通過該shared_ptr訪問繫結的物件。

動態陣列

盡量使用標準庫容器而不是動態陣列,通過在型別名後跟方括號來分配物件陣列,方括號中是陣列元素的個數。分配乙個陣列會得到乙個元素型別的指標,由於分配的記憶體並不是乙個陣列型別,因此不能對動態陣列呼叫begin和end,也不能使用範圍for語句。記住動態分配的陣列並不是陣列型別。

分配動態陣列時可以通過值初始化來初始化每個元素,方法是在方括號後面跟空的小括號,也可以使用列表初始化器來初始化陣列元素。值得注意的是在值初始化的空括號內不能給定初始化器。

可以動態分配乙個元素個數為0的陣列,new返回的是乙個合法的非空指標,但不能對該指標進行解引用,可以像使用尾後迭代器一樣使用該指標。

通過delete後面跟方括號來釋放動態分配的陣列,如果忘記寫方括號,程式的行為將是未定義的。

可以通過unique_ptr來管理動態陣列,通過在型別引數後面新增方括號使unique_ptr指向陣列,可以直接通過下標運算子來訪問陣列元素但是不能使用點運算子與箭頭運算子。無法直接使用shared_ptr直接管理動態陣列。

使用new分配記憶體時把記憶體分配與物件構造的過程合成在了一起,這限制了程式的靈活性。標準庫allocator類定義在標頭檔案memory中,它將記憶體分配與物件構造分離開來。使用可以分配的物件型別建立allocator物件,通過呼叫成員函式allocate()來分配記憶體空間,通過呼叫construct成員函式來初始化指定位置的物件。

《C Primer》第12章 動態記憶體

shared ptr允許多個指標指向同乙個物件,unique ptr獨佔所指向的物件,用make shared函式分配動態記憶體,返回物件的shared ptr.程式使用動態記憶體的原因之一是需要在多個物件間共享資料,自己直接管理記憶體的類與使用智慧型指標的類不同,它們不能依賴類的物件拷貝 賦值和銷...

C primer 12章 動態記憶體

這一章,由於本身對c語言動態分配以及指標比較熟悉,所以看起來會很輕鬆的。int i pi1 i pi2 nullptr double pd new double 33 pd1 pd const ini pci new const int 12 delete i 編譯器發現i不是指標,產生編譯錯誤資訊...

c primer第十二章動態記憶體小結 12

第十二章 動態記憶體 1.動態記憶體 c 中,動態記憶體管理是通過一對運算子完成的 new和delete。c語言中通過malloc與free函式來實現先動態記憶體的分配與釋放,c 中new與delete的實現其實會呼叫malloc與free。由於 c 語言沒有自動記憶體 機制,每次 new 出來的記...