目錄
C/C++內存管理
案例:變量在內存中到底會在哪?
New和delete
Operator new和operator delete函數
New和delete的原理
對內置類型
對自定義類型
定位new
New/delete和malloc/free的區別
C/C++內存管理
????????C/C++內存管理分布圖:(從語言的角度來看,數據段也稱為靜態區,代碼段也稱為常量區)
????????內存大小:理論上,32位計算機內存上限為4GB;64位計算機內存上限可達256T,實際上我們使用計算機一般為8G或16G或者32G,不會很大。
棧和堆細節:??
????????棧區先定義的變量放到棧底,地址高,后定義的變量放到棧頂,地址低,因此是棧是向下生長的,堆區則相反。
????????棧區主要存在局部變量和函數參數,其空間的管理由編譯器自動完成,無需手動控制,堆區是自己申請。
????????堆大小受限于操作系統,而棧空間一般由系統直接分配。
????????棧一般是進行靜態分配的,但也可以通過函數_alloca進行動態分配,不過注意,所分配空間不能通過free或delete進行釋放,而堆無法靜態分配,只能動態分配。
?????????在C語言中我們用malloc/calloc/realloc和free來在堆上管理堆上的空間,但在c++中進行了更新。在C++中我們用New和delete來管理堆上的空間。
????????Malloc和new的最大差別是:C語言malloc失敗后會返回NULL,C++New失敗后會自動報異常。
? ? ? ? 注意:使用malloc是需要頭文件malloc.h的,只是平時這個頭文件已經被其他頭文件所包含了,用的時候很少單獨引入。
案例:變量在內存中到底會在哪?
請填寫下列問題:
????????globalVar在哪里?__靜態區__ ?staticGlobalVar在哪里?_靜態區___
????????staticVar在哪里?__靜態區__ ?localVar在哪里?_棧___
????????num1 在哪里?_棧___
????????char2在哪里?_棧___ * char2在哪里?__棧_
(用數組存儲字符串,會在代碼段生成一串字符,然后到棧上開辟一段空間,把內容拷貝進去)
????????pChar3在哪里?_棧___ * pChar3在哪里?_代碼段(常量區)___
(用指針則是存放 代碼段內存放字符串的地址,所以解引用地址后會在代碼段)
????????ptr1在哪里?__棧__ * ptr1在哪里?_堆___
(prt1變量是在棧區創建的,所以在棧上,但申請的空間在堆上)
????????sizeof(num1) = __40__;
????????sizeof(char2) = _5___; ??strlen(char2) = __4__;(sizeof(數組)就是整個數組的大小)
????????sizeof(pChar3) = _4/8___; ??strlen(pChar3) = _4___;(sizeof(指針)則是看幾位計算機)
????????sizeof(ptr1) = __4/8__;
New和delete
????????創建單個對象:new 類型(內容);創建數組:new 類型[大小]{內容},開辟類對象的數組時(該類對象有用戶寫的析構函數,默認生成的不行),會在前面額外開辟4字節空間,用于存放類對象數組有多少個元素,讓delete數組時,調用類的析構函數時知道要調用幾次。C++把new當做一個操作符而不是函數。
????????Delete也分為兩種,釋放單個空間:delete 對象名;釋放一個數組:delete[] 對象名。
????????New和delete的使用方式如下:
????????在C++中,我們new一個類對象,編譯器會自動調用該類的構造函數。這樣就不需要像C語言malloc一個空間然后賦值那么麻煩。Delete也會調用該類的析構函數。
注意:new和delete一定要匹配使用,即new數組要用delete數組來釋放。
????????如果不匹配使用,對于內置類型和沒有自己寫析構函數的類一般不會出錯(默認生成析構函數是系統合成的沒有作用的析構函數,所以系統什么也不做,只用釋放空間,內置類型同理)
????????對于有自己寫析構函數的類,delete會調用析構函數,而new數組本來應該匹配delete數組來釋放,讓編譯器調用多次析構函數,但如果我們沒有匹配使用,如下圖,只用了delete a1,編譯器只會調用一次析構函數,編譯雖然能通過,但是運行會出斷言錯誤。
Operator new和operator delete函數
????????Operator new和operator delete函數是系統提供的全局函數,它們實際上是new和delete的底層代碼,new底層會調用operator new函數來申請空間;delete底層調用operator delete函數來釋放空間。
????????Operator new底層代碼也是通過malloc來開辟空間,即對malloc的封裝,如果空間不夠,則判斷一下malloc是否返回NULL;如果申請內存失敗了,這里會拋出bad_alloc類型異常,也就是new失敗之后返回的異常。Operator delete同理,是對free的封裝。
????????總之,operator new不是為我們準備的,而是為new準備的,主要是用來返回開辟空間異常的。
New和delete的原理
對內置類型
????????如果申請的是內置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。
對自定義類型
New:
????????調用operator new函數申請空間,然后在申請的空間上執行構造函數,完成對象的構造。
Delete:
????????在空間上執行析構函數,完成對象中資源的清理工作,然后調用operator delete函數釋放對象的空間
New[N]:
????????調用operator new[]函數,在operator new[]中實際調用operator new函數完成對N個對象空間的申請,在申請的空間上執行N次構造函數。
Delete[]:
????????在釋放的對象空間上執行N次析構函數,完成N個對象中資源的清理。(N是多少編譯器會知道,不需要填),然后調用operator delete[]釋放空間,實際上在operator delete[]中會調用operator delete來釋放空間。
定位new
????????定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。使用方法為:new(指針,指向開辟的空間)類型(要初始化的值),使用情況如下圖所示:
New/delete和malloc/free的區別
區別:
- malloc和free是函數,new和delete是操作符。
- malloc申請的空間不會初始化,new可以初始化。
- malloc申請空間時,需要手動計算空間大小并傳遞;new只需在其后跟上空間的類型即可,如果是多個對象,[]中指定對象個數即可。
- malloc的返回值為void*, 在使用時必須強轉;new不需要,因為new后跟的是空間的類型。
- malloc申請空間失敗時,返回的是NULL,因此使用時必須判空;new不需要,但是new需要捕獲異常。
- 申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數與析構函數,而new在申請空間后會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理。