1. 程式人生 > >C++ primer筆記----動態記憶體

C++ primer筆記----動態記憶體

1、 物件生命週期:全域性物件在程式啟動時分配,在程式結束時銷燬。區域性自動物件,當我們進入其定義所在程式塊時被建立,在離開塊時被銷燬。區域性static物件在第一次使用前分配,在程式結束時銷燬

2、除了static和自動物件外,C++還支援動態物件的分配。動態分配的物件的生存期與它們在哪裡建立無關,只有被顯示的釋放時,這些物件才會被銷燬

3、動態物件的釋放是程式設計中極其容易出問題的地方,為了安全使用動態物件,標準庫定義了兩個智慧指標型別來管理動態分配物件,當一個物件應該被釋放時,指向它的智慧指標可以確保自動釋放它

4、靜態記憶體:儲存區域性static物件、類static物件、定義在任何函式之外的物件,由編譯器自動建立和銷燬。棧記憶體:儲存定義在函式之內的非static物件,棧物件僅在定義的程式塊執行時才存在

5、除了靜態記憶體和棧記憶體,每個程式還擁有一個記憶體池,這部分記憶體被稱為自由空間或堆,程式用堆來儲存動態分配的物件:在程式執行時分配的物件,其生存週期由程式來控制,也就是說,當動態物件不再使用時,我們必須顯式的銷燬:必須正確的管理動態記憶體

6、C++中動態記憶體的管理是通過一對運算子來完成的,new:在動態記憶體中為物件分配空間並返回一個指向該物件的指標。delete:接受一個動態物件的指標,銷燬該物件,並釋放與之關聯的記憶體

7、忘記釋放記憶體:記憶體洩漏,在尚有指標引用記憶體的情況下釋放了記憶體,就會產生引用非法記憶體的指標

8、為了更安全的使用動態記憶體,新標準庫定義了兩種智慧指標型別來管理動態物件,標頭檔案為memory,智慧指標的主要作用就是自動釋放所指向的物件,shared_ptr型別允許多個指標指向同一物件,unique_ptr型別則獨佔所指向物件

9、智慧指標的使用方式與內建型別指標相似,解引用也是返回所指向物件,若在條件判斷中使用,檢測其是否為空

10、make_shared()函式:最安全的分配和使用動態記憶體的方法,此函式在動態記憶體中分配一個物件並初始化它,返回指向該物件的shared_ptr,標頭檔案為memory

每個shared_ptr都有一個關聯的計數器,稱為引用計數,個人理解就是該物件被引用的次數,拷貝情況下會遞增:
1:用一個shared_ptr初始化另一個shared_ptr(拷貝)
2:將一個shared_ptr傳遞給一個函式當引數,值傳遞(拷貝)
3:作為函式的返回值,(返回的是自身的拷貝,也就是活引用的次數+1)

計數器遞減情況:
1:給shared_ptr賦予一個新值(也就是說自身指向了另外一個地址,原來指向的物件已經沒有引用者,則會自動釋放)
2:一個shared_ptr離開其作用域時,會被銷燬(遞減)

當一個shared_ptr的計數器變為0,他就會自動釋放自己所管理的物件,前提是其指向的物件只有一個引用者。

11、當指向一個物件的最後一個shared_ptr被銷燬時,該物件會被自動銷燬:利用解構函式,會遞減該物件的引用計數,當引用次數變為0,會銷燬該物件,並釋放它佔用的記憶體

12、相關聯記憶體是否銷燬:所有指向該記憶體的shared_ptr物件都被銷燬,也就是計數器為0

13、使用動態記憶體的原因:讓多個物件共享相同的底層資料。也就是說拷貝的情況雖然發生,但是並不是元素的拷貝,而是將本身的指向拷貝給另一個指標物件,讓這一個物件也指向自己所指向的物件,這樣在本身釋放以後,還有另一個物件指向自身原來所指向的物件。

14、new和delete相對於智慧指標來說非常容易出錯,最好使用智慧指標來管理動態記憶體

15、在自由空間分配的記憶體是無名的,因此new無法為其分配物件命名,而是返回指向該物件的指標

16、預設情況下,new分配的物件是預設初始化的,這就說明內建型別或者組合型別將是未定義的(l例如:int,會指向一個為初始化的int),類型別物件將用預設建構函式進行初始化(例如string,會產生一個空string)。

17、建議使用值初始化(在最後加一對小括號即可),值初始化的內建型別物件有著良好定義的值

18、auto只有當括號中只有單一引數時可以使用,可以使用new分配const物件

19、delete完成兩個操作:銷燬給定指標所指向的物件,釋放對應的記憶體,delete的引數必須是指向動態分配的物件或是一個空指標。

20、內建型別指標管理的動態記憶體在被顯式的釋放前一直都會存在,因為內建型別與類型別不同,雖然內建型別的指標會在離開作用域後被銷燬,但是其記憶體依然存在

21、同一塊記憶體釋放兩次:兩個內建型別的指標指向同一塊自由空間分配的記憶體,在對一個指標進行delete之後,其指向的記憶體也會被釋放,若再對第二個指標進行delete,會造成自由空間破壞

22、忘記使用delete,使用已經釋放掉的物件都是經常發生的(使用new和delete時),所以儘可能的使用智慧指標

23、在很多機器上,即使delete了某個內建型別的指標(也就是說釋放了對應的記憶體空間),雖然指標已經無效,但是其仍然保留這釋放空間的對應地址,變成了空懸指標,也就是說我們要保留指標,可以將其置為空指標

24、理解變數的銷燬與其記憶體的釋放之間的關係:內建型別的指標在離開作用域時,本身會被銷燬,但是其指向的記憶體空間什麼都不會發生,必須以顯式的delete進行釋放空間。智慧指標在離開作用域時,本身也會被銷燬,並且計數器減一,當其計數器為0且只有一個智慧指標指向該物件時,該物件的記憶體空間會被釋放。如若用智慧指標的get()函式得到的一個內建指標來初始化一個臨時的智慧指標,一旦該內建指標被釋放,指向的記憶體也會被釋放,原來的智慧指標就會變成空指標

25、永遠不要用get初始化另一個智慧指標或是給智慧指標賦值,只有在確定程式碼不會delete指標的情況下,才能使用get

26、將一個新的指標賦給shared_ptr:利用reset()函式,會更新計數。

27、如果在new和delete之間發生了異常,且異常未被捕獲,則該記憶體就永遠不會被釋放!(非常危險!!!),而智慧指標只要離開作用域,計數器減一,則隨著智慧指標被銷燬,該塊記憶體也會被釋放,這就說明在實際使用過程中應使用shared_ptr來防止記憶體洩漏

28、正確的使用智慧指標:
1:不使用相同的內建指標值初始化多個智慧指標
2:不delete get()返回的指標
3:不使用get()初始化或reset另一個只能指標
4:當你使用的智慧指標管理的資源布氏new分配的記憶體,記住傳遞一個刪除器

29、unique_ptr擁有其所指向的物件,屬於一一對應關係,unique_ptr被銷燬時,其物件也會被銷燬,unique_ptr不支援拷貝和賦值,必須採用直接初始化的方式,當我們定義一個unique_ptr時,必須將其繫結到一個new返回的指標上

30、可以使用release():放棄對指標的控制權,返回指標,並將其置為空,和reset():如果提供了內建指標q,令u指向這個物件,否則將u置空,將指標的所有權轉移,但並沒有釋放記憶體

31、在unique_ptr快要被銷燬時,可以進行拷貝:返回unique_ptr指標,這是一種特殊的拷貝

32、weak_ptr:不控制所指向物件生命週期的智慧指標,使用時必須進行判斷物件是否存在

33、大多數的應用應該使用標準庫容器,而不是使用動態分配的陣列

34、用new分配的動態陣列會返回一個元素型別的指標,而並未得到陣列型別的物件

35、動態陣列並不是陣列型別,不能呼叫begin()和end()函式

36、釋放動態陣列時,需要在指標名前加 [ ] ,陣列中的元素按照逆序銷燬

37、字串字面常量不同於普通的區域性變數,具有static duration lifetime,這整個程式的生命週期中都將存在

38、new將記憶體分配與物件構造組合在了一起,而allocator將記憶體分配和物件構造分離,它提供一種型別感知的記憶體分配方法,它分配的記憶體是原始的、未構造的

39、利用allocator分配記憶體之後。必須在經過construnct進行構造物件,兩個引數分別為:建立物件位置的指標,元素型別的值

40、對構造後的元素進行destory操作,銷燬物件,deallocator