new 和 malloc
malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用于申請動態內存和釋放內存。 ?
? 對于非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函 數。由于malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于malloc/free。 ?
? 因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。 ?
? 我們先看一看malloc/free和new/delete如何實現對象的動態內存管理。 ?
? ?
? class ? Obj ?
? { ?
? public ? : ?
? Obj(void){ ? cout ? << ? “Initialization” ? << ? endl; ? } ?
? ~Obj(void){ ? cout ? << ? “Destroy” ? << ? endl; ? } ?
? void Initialize(void){ ? cout ? << ? “Initialization” ? << ? endl; ? } ?
? void ? ? ? ? Destroy(void){ ? cout ? << ? “Destroy” ? << ? endl; ? } ?
? }; ?
? void ? UseMallocFree(void) ?
? { ?
? Obj ? ? *a ? = ? (obj ? *)malloc(sizeof(obj)); // ? 申請動態內存 ?
? a->Initialize(); // ? 初始化 ?
? //… ?
? a->Destroy(); // ? 清除工作 ?
? free(a); // ? 釋放內存 ?
? } ?
? void ? UseNewDelete(void) ?
? { ?
? Obj ? ? *a ? = ? new ? Obj; // ? 申請動態內存并且初始化 ?
? //… ?
? delete ? a; // ? 清除并且釋放內存 ?
? } ?
? ? 用malloc/free和new/delete如何實現對象的動態內存管理 ?
? ?
? 類Obj的函數Initialize模擬了構造函數的功能,函數Destroy模擬了析構函數的功能。函數UseMallocFree中,由于 malloc/free不能執行構造函數與析構函數,必須調用成員函數Initialize和Destroy來完成初始化與清除工作。函數 UseNewDelete則簡單得多。 ?
? 所以我們不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由于內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。 ?
? 既然new/delete的功能完全覆蓋了malloc/free,為什么C++不把malloc/free淘汰出局呢?這是因為C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。 ?
? 如果用free釋放“new創建的動態對象”,那么該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內 存”,理論上講程序不會出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。??
? 對于非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函 數。由于malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于malloc/free。 ?
? 因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。 ?
? 我們先看一看malloc/free和new/delete如何實現對象的動態內存管理。 ?
? ?
? class ? Obj ?
? { ?
? public ? : ?
? Obj(void){ ? cout ? << ? “Initialization” ? << ? endl; ? } ?
? ~Obj(void){ ? cout ? << ? “Destroy” ? << ? endl; ? } ?
? void Initialize(void){ ? cout ? << ? “Initialization” ? << ? endl; ? } ?
? void ? ? ? ? Destroy(void){ ? cout ? << ? “Destroy” ? << ? endl; ? } ?
? }; ?
? void ? UseMallocFree(void) ?
? { ?
? Obj ? ? *a ? = ? (obj ? *)malloc(sizeof(obj)); // ? 申請動態內存 ?
? a->Initialize(); // ? 初始化 ?
? //… ?
? a->Destroy(); // ? 清除工作 ?
? free(a); // ? 釋放內存 ?
? } ?
? void ? UseNewDelete(void) ?
? { ?
? Obj ? ? *a ? = ? new ? Obj; // ? 申請動態內存并且初始化 ?
? //… ?
? delete ? a; // ? 清除并且釋放內存 ?
? } ?
? ? 用malloc/free和new/delete如何實現對象的動態內存管理 ?
? ?
? 類Obj的函數Initialize模擬了構造函數的功能,函數Destroy模擬了析構函數的功能。函數UseMallocFree中,由于 malloc/free不能執行構造函數與析構函數,必須調用成員函數Initialize和Destroy來完成初始化與清除工作。函數 UseNewDelete則簡單得多。 ?
? 所以我們不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由于內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。 ?
? 既然new/delete的功能完全覆蓋了malloc/free,為什么C++不把malloc/free淘汰出局呢?這是因為C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。 ?
? 如果用free釋放“new創建的動態對象”,那么該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內 存”,理論上講程序不會出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。??
函數malloc的原型如下: ?
? void ? * ? malloc(size_t ? size); ?
? 用malloc申請一塊長度為length的整數類型的內存,程序如下: ?
? int ? ? *p ? = ? (int ? *) ? malloc(sizeof(int) ? * ? length); ?
? 我們應當把注意力集中在兩個要素上:“類型轉換”和“sizeof”。 ?
? malloc返回值的類型是void ? *,所以在調用malloc時要顯式地進行類型轉換,將void ? * ? 轉換成所需要的指針類型。malloc函數本身并不識別要申請的內存是什么類型,它只關心內存的總字節數。我們通常記不住int, ? float等數據類型的變量的確切字節數。 ?
? ?
? 運算符new使用起來要比函數malloc簡單得多,例如: ?
? int ? ? *p1 ? = ? (int ? *)malloc(sizeof(int) ? * ? length); ?
? int ? ? *p2 ? = ? new ? int[length]; ?
? 這是因為new內置了sizeof、類型轉換和類型安全檢查功能。對于非內部數據類型的對象而言,new在創建動態對象的同時完成了初始化工作。如果對象有多個構造函數,那么new的語句也可以有多種形式。例如 ?
? class ? Obj ?
? { ?
? public ? : ?
? Obj(void); // ? 無參數的構造函數 ?
? Obj(int ? x); // ? 帶一個參數的構造函數 ?
? … ?
? } ?
? void ? Test(void) ?
? { ?
? Obj ? ? *a ? = ? new ? Obj; ?
? Obj ? ? *b ? = ? new ? Obj(1); // ? 初值為1 ?
? … ?
? delete ? a; ?
? delete ? b; ?
? } ?
? 如果用new創建對象數組,那么只能使用對象的無參數構造函數。
? void ? * ? malloc(size_t ? size); ?
? 用malloc申請一塊長度為length的整數類型的內存,程序如下: ?
? int ? ? *p ? = ? (int ? *) ? malloc(sizeof(int) ? * ? length); ?
? 我們應當把注意力集中在兩個要素上:“類型轉換”和“sizeof”。 ?
? malloc返回值的類型是void ? *,所以在調用malloc時要顯式地進行類型轉換,將void ? * ? 轉換成所需要的指針類型。malloc函數本身并不識別要申請的內存是什么類型,它只關心內存的總字節數。我們通常記不住int, ? float等數據類型的變量的確切字節數。 ?
? ?
? 運算符new使用起來要比函數malloc簡單得多,例如: ?
? int ? ? *p1 ? = ? (int ? *)malloc(sizeof(int) ? * ? length); ?
? int ? ? *p2 ? = ? new ? int[length]; ?
? 這是因為new內置了sizeof、類型轉換和類型安全檢查功能。對于非內部數據類型的對象而言,new在創建動態對象的同時完成了初始化工作。如果對象有多個構造函數,那么new的語句也可以有多種形式。例如 ?
? class ? Obj ?
? { ?
? public ? : ?
? Obj(void); // ? 無參數的構造函數 ?
? Obj(int ? x); // ? 帶一個參數的構造函數 ?
? … ?
? } ?
? void ? Test(void) ?
? { ?
? Obj ? ? *a ? = ? new ? Obj; ?
? Obj ? ? *b ? = ? new ? Obj(1); // ? 初值為1 ?
? … ?
? delete ? a; ?
? delete ? b; ?
? } ?
? 如果用new創建對象數組,那么只能使用對象的無參數構造函數。
?
區別兩個 ?
? ?
? 1 ? new是操作符 ?
? ? ? malloc是庫函數 ?
? ?
? 2 ? new可以調用構造函數,malloc不可以 ?
? ?
? ?
? 還有,這兩個函數不存在內存分配大小問題 ?
? 這兩個操作是在堆里面申請內存空間,除非空間不夠了,返回BULL指針,否則都沒有問題的,如果你出現了某種情況,看看是不是其它的問題。??
new ? 最終調用的是HeapAlloc,而HeapAlloc聲明如下: ?
? LPVOID ? HeapAlloc( ?
? ? ? HANDLE ? hHeap, ? ? // ? handle ? to ? the ? private ? heap ? block ?
? ? ? DWORD ? dwFlags, ? // ? heap ? allocation ? control ? flags ?
? ? ? DWORD ? dwBytes ? ? // ? number ? of ? bytes ? to ? allocate ?
? ); ?
? 其中第一個參數必須是HeapCreate或GetProcessHeap ? 函數的返回句柄。 ?
? 如果是HeapCreate的話(如下:) ?
? HANDLE ? HeapCreate( ?
? ? ? DWORD ? flOptions, ? ? ? ? ? ? // ? heap ? allocation ? flag ?
? ? ? DWORD ? dwInitialSize, ? ? // ? initial ? heap ? size ?
? ? ? DWORD ? dwMaximumSize ? ? ? // ? maximum ? heap ? size ?
? ); ?
? 那么當該函數的最后一個參數非0時,所創建的堆要比0x7FFF8(512k)略小。如果為0,則大小受到可用內存的限制。 ?
? 還有,new申請的內存不可移動,會造成內存碎片。
? ?
? 1 ? new是操作符 ?
? ? ? malloc是庫函數 ?
? ?
? 2 ? new可以調用構造函數,malloc不可以 ?
? ?
? ?
? 還有,這兩個函數不存在內存分配大小問題 ?
? 這兩個操作是在堆里面申請內存空間,除非空間不夠了,返回BULL指針,否則都沒有問題的,如果你出現了某種情況,看看是不是其它的問題。??
new ? 最終調用的是HeapAlloc,而HeapAlloc聲明如下: ?
? LPVOID ? HeapAlloc( ?
? ? ? HANDLE ? hHeap, ? ? // ? handle ? to ? the ? private ? heap ? block ?
? ? ? DWORD ? dwFlags, ? // ? heap ? allocation ? control ? flags ?
? ? ? DWORD ? dwBytes ? ? // ? number ? of ? bytes ? to ? allocate ?
? ); ?
? 其中第一個參數必須是HeapCreate或GetProcessHeap ? 函數的返回句柄。 ?
? 如果是HeapCreate的話(如下:) ?
? HANDLE ? HeapCreate( ?
? ? ? DWORD ? flOptions, ? ? ? ? ? ? // ? heap ? allocation ? flag ?
? ? ? DWORD ? dwInitialSize, ? ? // ? initial ? heap ? size ?
? ? ? DWORD ? dwMaximumSize ? ? ? // ? maximum ? heap ? size ?
? ); ?
? 那么當該函數的最后一個參數非0時,所創建的堆要比0x7FFF8(512k)略小。如果為0,則大小受到可用內存的限制。 ?
? 還有,new申請的內存不可移動,會造成內存碎片。
?
?
內存分配最終都堆(HEAP)上操作,允許的最大空間是_HEAP_MAXREQ=0xFFFFFFE0,但C運行庫會在每次額外分配一個
_CrtMemBlockHeader結構在該次分配的內存起始處,同時在結束處多分配nNoMansLadnSize=4個字節的內存用于檢測檢查調
試.因此通常的高效內存管理技術都是將多次小空間分配合并成一次大空間分配,或只進行一次分配,回收時不釋放以直接用于下次分配的 ? . ?
? 可分配空間并不等于一定可以分配到,這受環境的直接影響,如頁文件的大小,系統已經占用的空間等. ?
? 當所給參數太大,會有運行時警告:Invalid ? allocation ? size: ? %u ? bytes.
? 可分配空間并不等于一定可以分配到,這受環境的直接影響,如頁文件的大小,系統已經占用的空間等. ?
? 當所給參數太大,會有運行時警告:Invalid ? allocation ? size: ? %u ? bytes.
posted on 2007-10-29 00:50 旅途 閱讀(609) 評論(0) 編輯 收藏 引用 所屬分類: C/C++