?
目錄
1、C/C++內存分布
2.、C語言中動態(tài)內存管理方式:malloc、calloc、realloc
3、C++內存管理方式
3.1 new/delete操作內置類型
3.2 new和delete操作自定義類型
3.3 malloc與new的異常處理機制
4、operator new與operator delete函數
4.1 operator new與operator delete函數
4.1.1 operator new源碼
4.1.2 operator delete源碼
5、new和delete的實現原理
5.1 內置類型
5.2 自定義類型
5.2.1 new的原理
5.2.2 delete的原理
5.2.3new T[N]的原理
5.2.4 delete[]的原理
6、定位new表達式(了解)
7、malloc/free和new/delete的區(qū)別
7.1 malloc/free和new/delete 相同點
7.2 malloc/free和new/delete 不相同點
1、C/C++內存分布
我們先來了解一下C/C++內存分配的幾個區(qū)域,以下面的代碼為例來看:
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
說明:
1. 棧又叫堆棧--非靜態(tài)局部變量/函數參數/返回值等等,棧是向下增長的。
2. 內存映射段是高效的I/O映射方式,用于裝載一個共享的動態(tài)內存庫。用戶可使用系統(tǒng)接口創(chuàng)建共享共享內存,做進程間通信。3. 堆用于程序運行時動態(tài)內存分配,堆是可以上增長的。
4. 數據段/靜態(tài)區(qū)--存儲全局數據和靜態(tài)數據。
5. 代碼段/常量區(qū)--可執(zhí)行的代碼/只讀常量。
2.、C語言中動態(tài)內存管理方式:malloc、calloc、realloc
malloc:向內存申請一塊空間,成功的話返回內存塊的指針,失敗返回空指針(NULL);
calloc:向內存申請一塊空間,并逐字節(jié)初始化為0,成功的話返回內存塊的指針,失敗返回空指針(NULL);
realloc:調整動態(tài)開辟的內存大小。
我們以代碼舉例來看看:
int mian()
{
int* p1 = (int*)malloc(sizeof(int));
int* p2 = (int*)realloc(p1, sizeof(int) * 10);// 擴容,若是異地擴容realloc會將p1的內容
free(p2); // 拷貝到p2開出的內存中并釋放掉p1的內存
int* p3 = (int*)calloc(1, sizeof(int));// 開辟四個字節(jié)空間,并初始化為 1
free(p3);
return 0;
}
3、C++內存管理方式
C語言內存管理方式在C++中可以繼續(xù)使用,但有些地方就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過new和delete操作符進行動態(tài)內存管理。
3.1 new/delete操作內置類型
int main()
{
// 管理對象
// 動態(tài)開辟一個int類型的空間
int* p1 = new int;
// 動態(tài)開辟一個int類型的空間,并初始化為1
int* p2 = new int(1);
//管理對象數組
// 動態(tài)開辟一個int類型的數組
int* p3 = new int[10];
// 動態(tài)開辟一個int類型的數組,并初始化
int* p4 = new int[10]{};// 不寫初始化值,默認初始化為 0
// 動態(tài)開辟一個int類型的數組,并初始化
int* p5 = new int[10]{ 1,2,3 };// 前三個分別初始化為1 2 3,后面默認初始化為 0
//釋放開辟的內存
delete p1;
delete p2;
delete[] p3;// 對應釋放數組加[]
delete[] p4;
delete[] p5;
return 0;
}
我們啟動監(jiān)視窗口看看結果:
注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續(xù)的空間,使用new[]和delete[],注意:匹配起來使用。
3.2 new和delete操作自定義類型
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
A* a1 = (A*)malloc(sizeof(A));
A* a2 = new A;
free(a1);
delete(a2);
return 0;
}
我們來看看malloc、new開辟動態(tài)內存 與 free、delete釋放內存。
我們先來看結果:
這里分別自動調用了一次構造函數與析構函數。這里到底是誰調用的呢?
對于C語言來說,是不存在構造函數的,因此C語言設計的malloc是不會自動調用構造函數的,free也是不會調用析構函數,但是對于C++來講,是面向對象的,new與delete會在開辟與釋放內存時調用構造函數與析構函數。
注意:在申請自定義類型的空間時,new會調用構造函數,delete會調用析構函數,而malloc與free不會。
3.3 malloc與new的異常處理機制
int main()
{
int* p1 = (int*)malloc(1024 * 1024 * 1024);
cout << p1 << endl;
int* p2 = (int*)malloc(1024 * 1024 * 1024);
cout << p2 << endl;
try
{
char* p3 = new char[0x7fffffff];
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
當malloc失敗時返回空指針,而new失敗了會拋異常。
new失敗后,直接會跳到異常捕獲語句,不執(zhí)行new后面的代碼,如果我們不捕獲異常程序就會終止掉。異常的捕獲只會在try、catch里面,不在里面就不會捕獲異常。
4、operator new與operator delete函數
4.1 operator new與operator delete函數
C++的標準庫里提供了operator new與operator delete函數,但是這兩個函數不是重載,只是名字像重載,是系統(tǒng)提供的兩個全局函數,new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間。
我們來分別看看源碼:
4.1.1 operator new源碼
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
operator new里封裝了malloc,失敗了會拋異常,
4.1.2 operator delete源碼
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的實現
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
總結:通過上述兩個全局函數的實現知道,operator new 實際也是通過malloc來申請空間,如果malloc申請空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應對措施,如果用戶提供該措施就繼續(xù)申請,否則就拋異常。operator delete 最終是通過free來釋放空間的。
5、new和delete的實現原理
5.1 內置類型
如果申請的是內置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續(xù)空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。
5.2 自定義類型
5.2.1 new的原理
1. 調用operator new函數申請空間
2. 在申請的空間上執(zhí)行構造函數,完成對象的構造
5.2.2 delete的原理
1. 在空間上執(zhí)行析構函數,完成對象中資源的清理工作
2. 調用operator delete函數釋放對象的空間
5.2.3new T[N]的原理
1. 調用operator new[]函數,在operator new[]中實際調用operator new函數完成N個對象空間的申請
2. 在申請的空間上執(zhí)行N次構造函數
5.2.4 delete[]的原理
1. 在釋放的對象空間上執(zhí)行N次析構函數,完成N個對象中資源的清理
2. 調用operator delete[]釋放空間,實際在operator delete[]中調用operator delete來釋放空間
6、定位new表達式(了解)
定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象。
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必須是一個指針,initializer-list是類型的初始化列表
使用場景:
定位new表達式在實際中一般是配合內存池使用。因為內存池分配出的內存沒有初始化,所以如果是自定義類型的對象,需要使用new的定義表達式進行顯示調構造函數進行初始化。
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// p1現在指向的只不過是與A對象相同大小的一段空間,還不能算是一個對象,因為構造函數沒
有執(zhí)行
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; // 顯示調用構造函數 注意:如果A類的構造函數有參數時,此處需要傳參
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);// 顯示調用構造函數
p2->~A();
operator delete(p2);
return 0;
}
7、malloc/free和new/delete的區(qū)別
7.1 malloc/free和new/delete 相同點
都是從堆上申請空間,并且需要用戶手動釋放文章來源:http://www.zghlxwxcb.cn/news/detail-645426.html
7.2 malloc/free和new/delete 不相同點
1. malloc和free是函數,new和delete是操作符
2. malloc申請的空間不會初始化,new可以初始化
3. malloc申請空間時,需要手動計算空間大小并傳遞,new只需在其后跟上空間的類型即可,如果是多個對象,[]中指定對象個數即可
4. malloc的返回值為void*, 在使用時必須強轉,new不需要,因為new后跟的是空間的類型
5. malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常
6. 申請自定義類型對象時,malloc/free只會開辟空間,不會調用構造函數與析構函數,而new在申請空間后會調用構造函數完成對象的初始化,delete在釋放空間前會調用析構函數完成空間中資源的清理文章來源地址http://www.zghlxwxcb.cn/news/detail-645426.html
到了這里,關于[C++] 一篇帶你了解C++中動態(tài)內存管理,new讓大家都有對象的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!