C++之內(nèi)存分配new與delete使用方式
C++ new 和 delete
在C++中,new 和 delete 是用于動態(tài)內(nèi)存分配和釋放的運算符。
它們允許程序在運行時管理堆內(nèi)存,是實現(xiàn)動態(tài)數(shù)據(jù)結(jié)構(gòu)(如鏈表、樹)和靈活資源管理的基礎(chǔ)。
1. 基本語法
new 運算符
- 分配單個對象:
Type* ptr = new Type; // 默認初始化(內(nèi)置類型值未定義)
Type* ptr = new Type(value); // 直接初始化
Type* ptr = new Type{value}; // 列表初始化(C++11起)- 分配數(shù)組:
Type* arr = new Type[size]; // 分配包含size個元素的數(shù)組
- 值初始化:
Type* ptr = new Type(); // 值初始化為0或默認構(gòu)造函數(shù)
delete 運算符
- 釋放單個對象:
delete ptr; // 調(diào)用析構(gòu)函數(shù)(如有)并釋放內(nèi)存
- 釋放數(shù)組:
delete[] arr; // 釋放數(shù)組內(nèi)存,需使用[]告知編譯器釋放多個對象
2. 工作原理
new 的執(zhí)行步驟
- 內(nèi)存分配:調(diào)用
operator new(或operator new[]用于數(shù)組)分配原始內(nèi)存。 - 構(gòu)造函數(shù)調(diào)用:在分配的內(nèi)存上調(diào)用對象的構(gòu)造函數(shù)(若為類類型)。
delete 的執(zhí)行步驟
- 析構(gòu)函數(shù)調(diào)用:對對象調(diào)用析構(gòu)函數(shù)(若為類類型)。
- 內(nèi)存釋放:調(diào)用
operator delete(或operator delete[])釋放內(nèi)存。
3. 深入理解 new 和 delete
原始內(nèi)存操作
operator new 和 operator delete:
底層函數(shù),可被重載以自定義內(nèi)存分配行為。
void* operator new(size_t size); // 分配單個對象 void* operator new[](size_t size); // 分配數(shù)組 void operator delete(void* ptr); // 釋放單個對象 void operator delete[](void* ptr); // 釋放數(shù)組
示例:
void* raw_memory = operator new(sizeof(int)); // 分配原始內(nèi)存 int* ptr = static_cast<int*>(raw_memory); // 轉(zhuǎn)換為int指針 *ptr = 42; // 手動賦值 operator delete(ptr); // 釋放內(nèi)存(不調(diào)用析構(gòu)函數(shù))
定位 new(Placement New)
在已分配的內(nèi)存上構(gòu)造對象:
void* buffer = operator new(sizeof(MyClass)); // 分配原始內(nèi)存 MyClass* obj = new (buffer) MyClass(); // 在buffer上構(gòu)造對象 obj->~MyClass(); // 顯式調(diào)用析構(gòu)函數(shù) operator delete(buffer); // 釋放內(nèi)存
4. 數(shù)組的動態(tài)分配
分配與釋放數(shù)組
int* arr = new int[10]; // 分配10個int的數(shù)組
delete[] arr; // 釋放數(shù)組
// 多維數(shù)組
int** matrix = new int*[5]; // 分配5行
for (int i = 0; i < 5; ++i) {
matrix[i] = new int[10]; // 每行10列
}
// 釋放
for (int i = 0; i < 5; ++i) {
delete[] matrix[i];
}
delete[] matrix;數(shù)組初始化
int* arr = new int[5]{1, 2, 3, 4, 5}; // C++11起支持列表初始化在對數(shù)組進行動態(tài)分配時,會自動在之前多分配一塊空間用來儲存所要開辟的空間個數(shù),以便將來用delete釋放空間。
5.new和delete的實現(xiàn)原理
5.1 內(nèi)置類型
如果申請的是內(nèi)置類型的空間,new和malloc,delete和free基本類似,不同的地方是:
new/delete申請和釋放的是單個元素的空間,new[]和delete[]申請的是連續(xù)空間,而且new在申請空間失敗時會拋異常,malloc會返回NULL。
5.2 自定義類型
new的原理
- 調(diào)用operator new函數(shù)申請空間
- 在申請的空間上執(zhí)行構(gòu)造函數(shù),完成對象的構(gòu)造
delete的原理
- 在空間上執(zhí)行析構(gòu)函數(shù),完成對象中資源的清理工作
- 調(diào)用operator delete函數(shù)釋放對象的空間
new T[N]的原理
- 調(diào)用operator new[]函數(shù),在operator new[]中實際調(diào)用operator new函數(shù)完成N個對象空間的申請
- 在申請的空間上執(zhí)行N次構(gòu)造函數(shù)
delete[]的原理
- 在釋放的對象空間上執(zhí)行N次析構(gòu)函數(shù),完成N個對象中資源的清理
- 調(diào)用operator delete[]釋放空間,實際在operator delete[]中調(diào)用operator delete來釋放空間
6. 常見問題與注意事項
內(nèi)存泄漏
原因:忘記調(diào)用 delete 釋放 new 分配的內(nèi)存。
示例:
void leak() {
int* ptr = new int; // 分配內(nèi)存
// 未釋放內(nèi)存就返回
} // 內(nèi)存泄漏!懸空指針
原因:釋放內(nèi)存后仍保留指向該內(nèi)存的指針。
示例:
int* ptr = new int; delete ptr; *ptr = 10; // 懸空指針解引用,未定義行為
重復(fù)釋放
原因:多次釋放同一塊內(nèi)存。
示例:
int* ptr = new int; delete ptr; delete ptr; // 重復(fù)釋放,未定義行為
混用 delete 和 delete[]
錯誤示例:
int* arr = new int[10]; delete arr; // 錯誤!應(yīng)使用delete[]
對于內(nèi)置類型,程序會崩潰;而對于自定義類型,程序不會崩潰。
7. 自定義內(nèi)存管理
重載全局 operator new 和 operator delete
void* operator new(size_t size) {
void* p = malloc(size);
// 可添加內(nèi)存分配日志、性能監(jiān)控等
return p;
}
void operator delete(void* p) noexcept {
free(p);
// 可添加內(nèi)存釋放日志等
}類特定的內(nèi)存管理
class MyClass {
public:
static void* operator new(size_t size) {
// 自定義分配邏輯
return ::operator new(size);
}
static void operator delete(void* p) noexcept {
// 自定義釋放邏輯
::operator delete(p);
}
};8. 與C語言內(nèi)存管理的對比
| 特性 | C++ new/delete | C語言 malloc/free |
|---|---|---|
| 類型安全 | 自動推導(dǎo)類型,無需強制轉(zhuǎn)換 | 需要顯式轉(zhuǎn)換(如 (int*)malloc()) |
| 構(gòu)造/析構(gòu)函數(shù) | 自動調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù) | 不調(diào)用構(gòu)造/析構(gòu)函數(shù) |
| 初始化 | 支持直接初始化和列表初始化 | 僅分配內(nèi)存,不初始化值 |
| 數(shù)組語法 | 直接使用 new Type[size] | 需要計算總大?。ㄈ?malloc(size*sizeof(Type))) |
| 智能指針支持 | 與標(biāo)準(zhǔn)庫智能指針無縫配合 | 需手動封裝為智能指針 |
malloc/free和new/delete的共同點是:都是從堆上申請空間,并且需要用戶手動釋放。
不同的地方是:
- malloc和free是函數(shù),new和delete是操作符
- malloc申請的空間不會初始化,new可以初始化
- malloc申請空間時,需要手動計算空間大小并傳遞,new只需在其后跟上空間的類型即可, 如果是多個對象,[]中指定對象個數(shù)即可
- malloc的返回值為void*, 在使用時必須強轉(zhuǎn),new不需要,因為new后跟的是空間的類型
- malloc申請空間失敗時,返回的是NULL,因此使用時必須判空,new不需要,但是new需要捕獲異常
- 申請自定義類型對象時,malloc/free只會開辟空間,不會調(diào)用構(gòu)造函數(shù)與析構(gòu)函數(shù),而new在申請空間后會調(diào)用構(gòu)造函數(shù)完成對象的初始化,delete在釋放空間前會調(diào)用析構(gòu)函數(shù)完成空間中資源的清理釋放
總結(jié)
new/delete 是C++動態(tài)內(nèi)存分配的核心機制,適用于:
- 需要在運行時確定對象生命周期。
- 實現(xiàn)動態(tài)數(shù)據(jù)結(jié)構(gòu)(如鏈表、樹)。
- 優(yōu)先使用智能指針:現(xiàn)代C++中,
std::unique_ptr和std::shared_ptr能有效避免內(nèi)存泄漏,提高代碼安全性。 - 謹慎手動管理內(nèi)存:必須確保
new和delete配對使用,避免懸空指針和重復(fù)釋放。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

