網站首頁 編程語言 正文
C語言的動態內存管理函數(malloc、calloc、realloc、free) 雖然可以繼續在 C++ 使用,但是對于自定義類型成員而言,這些函數不會自動調用構造函數和析構函數,于是 C++ 增加了 new 和 delete 關鍵字
一、new和delete的使用
new 和 delete 用于在堆上申請或釋放一個元素的空間,new[] 和 delete[] 用于在堆上申請或釋放一塊連續的空間,對于自定義類型空間的開辟,new 和 delete 還會調用構造函數和析構函數
#include <iostream>
using namespace std;
class Demo
{
public:
Demo(int a1 = 10, int a2 = 20)
: _a1(a1)
, _a2(a2)
{
cout << "Demo()" << endl;
}
void print()
{
cout << _a1 << " " << _a2 << endl;
}
~Demo()
{
cout << "~Demo()" << endl;
}
private:
int _a1;
int _a2;
};
void printIntArr(int* arr, int len)
{
for (int i = 0; i < len; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
void printDemoArr(Demo* arr, int len)
{
for (int i = 0; i < len; ++i)
{
arr[i].print();
}
cout << endl;
}
int main()
{
//用 new 申請一個內置類型變量的空間
int* pint1 = new int;
cout << *pint1 << endl; //輸出 -842150451
//使用括號中的值初始化變量
int* pint2 = new int(5);
cout << *pint2 << endl; //輸出 5
//用 delete 釋放一個變量的空間
delete pint1;
delete pint2;
//用 new 申請一個自定義類型對象的空間,申請后會自動調用構造函數
Demo* pd1 = new Demo; //輸出 Demo()
pd1->print(); //輸出 10 20
//自定義類型會根據括號中的參數調用對應的構造函數
Demo* pd2 = new Demo(5, 5); //輸出 Demo()
pd2->print(); //輸出 5 5
//用 delete 釋放一個變量的空間,釋放前會自動調用析構函數
delete pd1; //輸出 ~Demo()
delete pd2; //輸出 ~Demo()
//對內置類型用 new[] 開辟一塊連續的空間
int* pint3 = new int[5]; //[]中表示開辟整形的個數
printIntArr(pint3, 5); //輸出 -842150451 -842150451 -842150451 -842150451 -842150451
//用花括號中的值初始化開辟的連續空間,未給值的為 0
int* pint4 = new int[5]{ 1, 2, 3, 4 };
printIntArr(pint4, 5); //輸出 1 2 3 4 0
//對內置類型用 delete[] 釋放一塊連續的空間
delete[] pint3;
delete[] pint4;
//對自定義類型用 new[] 開辟一塊連續的空間
//申請后會對空間自動調用構造函數 5 次
Demo* pd3 = new Demo[5]; //輸出 5 行 Demo()
printDemoArr(pd3, 5); //輸出 5 行 10 20
//用花括號中的值初始化開辟的連續空間
//花括號中如果用小括號會被認為是逗號表達式,會去調用單參的構造函數
//調用多參構造函數應在花括號中使用花括號,未給的值根據構造函數決定
Demo* pd4 = new Demo[5]{ (1, 2), {5}, {5, 10}}; //輸出 5 行 Demo()
printDemoArr(pd4, 5); //輸出 第一行 2 20,第二行 5 10 第三行 5 10,兩行 10 20
//對自定義類型用 delete[] 釋放一塊連續的空間
//釋放之前會對空間自動調用析構函數 5 次
delete[] pd3; //輸出 5 行 ~Demo
delete[] pd4; //輸出 5 行 ~Demo
return 0;
}
二、operator new和operator delete函數
operator new 和 operator delete 是系統提供的全局函數,不是 new 和 delete 的運算符重載函數
- operator new 底層是通過 malloc 函數來申請空間,當空間申請成功時直接返回,失敗時拋出異常(不會返回 nullptr),operator new 函數可以像 malloc 一樣使用,只是失敗時的處理不同
- operator delete 和 free 底層都是是通過 _free_dbg 函數釋放空間,只不過 operator delete 會對釋放前后進行一些檢查
#include <iostream>
using namespace std;
int main()
{
//operator new 和 malloc 使用方法一樣
//operator new 申請空間失敗時拋異常
int* pi = (int*)operator new(sizeof(int) * 4);
//operator delete 和 free 使用方法一樣,都會調用 _free_dbg
//operator delete 在釋放空間時會做一些檢查
operator delete(pi);
return 0;
}
operator new[] 和 operator delete[] 也是系統提供的全局函數,內部是通過調用 operator new 和 operator delete 函數
三、new和delete的實現原理
如果是內置類型,new 和 delete 調用 operator new 和 operator delete,new[] 和 delete[] 調用 operator new[] 和 operator delete[]
如果是自定義類型:
#include <iostream>
using namespace std;
class Demo
{
public:
Demo(int a1 = 10, int a2 = 20);
~Demo();
private:
int _a1;
int _a2;
};
Demo::Demo(int a1, int a2)
: _a1(a1)
, _a2(a2)
{
cout << "Demo()" << endl;
}
Demo::~Demo()
{
cout << "~Demo()" << endl;
}
int main()
{
Demo* pd1 = new Demo(5, 5);
delete pd1;
Demo* pd2 = new Demo[2]{ {1, 2}, {2, 3} };
delete[] pd2;
return 0;
}
new:
1. 調用 operator new 函數申請空間
2. 在申請的空間上執行構造函數,完成對象的構造
delete:
1. 在空間上執行析構函數,完成對象中資源的清理工作
2. 調用operator delete函數釋放對象的空間
new 類型[N]:
1. 調用operator new[] 函數,實際上是在 operator new[] 中調用 operator new 函數完成 N 個對象空間的申請
2. 在申請的空間上執行 N 次構造函數
delete[]:
1. 在釋放的對象空間上執行 N 次析構函數,完成 N 個對象中資源的清理
2. 調用 operator delete[] 釋放空間,實際上時在 operator delete[] 中調用 operator delete 來釋放空間
四、申請空間和釋放空間應配套使用
malloc/free、new/delete、new[]/delete[] 需要配套使用,否則總會有出問題的時候
下述代碼不會報錯,會產生內存泄漏
#include <iostream>
using namespace std;
class Stack
{
public:
Stack(int capacity = 4)
: _a(new int[capacity])
, _top(0)
, _capacity(capacity)
{
}
~Stack()
{
if (_a)
{
delete[] _a;
_top = _capacity = 0;
}
}
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack* ps = new Stack;
//free(ps); //內存泄漏
//delete 釋放內存之前會調用析構函數
delete ps; //正確寫法
return 0;
}
下述代碼在 vs2022 下會崩潰
#include <iostream>
using namespace std;
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << endl;
}
~A()
{
cout << "~A():" << endl;
}
private:
int _a;
};
int main()
{
A* p1 = new A[10];
//free(p1); //崩潰
delete[] p1; //正確寫法
A* p2 = new A[10];
//delete p2; //崩潰
delete[] p2; //正確寫法
return 0;
}
注意:不同的編譯器處理可能不同,這里只代表在 vs2022 編譯器中
五、定位new表達式
定位 new 表達式是在已開辟好的原始內存空間上調用構造函數初始化一個對象,使用格式:
new(place_address)type 或者 new(place_address)type(initializer-list)
place_address 必須是一個指針,initializer-list 是類型的初始化列表
定位 new 表達式在實際中一般是配合 內存池 使用,因為內存池分配出的內存沒有初始化,并且構造函數不可以顯示調用,所以如果是自定義類型的對象,需要使用定位 new 以進行顯示調用構造函數進行初始化
#include <iostream>
using namespace std;
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
//定位 new 又叫 replacement new
int main()
{
//p1 現在指向的只是與 A 對象相同大小的一段空間,并不是一個對象,因為沒有調用構造函數
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; //調用無參的構造函數 輸出 A()
//可以手動調用析構函數,然后釋放空間
p1->~A(); //輸出 ~A()
free(p1);
//p2 現在指向的只是與 A 對象相同大小的一段空間,并不是一個對象,因為沒有調用構造函數
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10); //10 是參數,可以根據參數調用對應的構造函數 輸出 A()
p2->~A(); //輸出 ~A()
operator delete(p2);
return 0;
}
六、malloc/free和new/delete的區別
malloc/free 和 new/delete 的共同點是:都是從堆上申請空間,并且需要用戶手動釋放
不同的地方是:
- malloc 和 free 是函數,new 和 delete 是運算符
- malloc 申請的空間不會初始化,new 可以初始化
- malloc 申請空間時,需要手動計算空間大小并傳遞,new 只需在其后跟上空間的類型,如果是多個對象,[] 中指定對象個數即可
- malloc 的返回值為 void*,接收時必須強制類型轉換,new 不需要,因為 new 后跟的是空間的類型
- malloc 申請空間失敗時,返回的是NULL,因此使用時必須判空,new 不需要,但是 new 需要捕獲異常
- 申請自定義類型對象時,malloc/free 只會開辟空間,不會調用構造函數與析構函數,而 new 在申請空間后會調用構造函數完成對象的初始化,delete 在釋放空間前會調用析構函數完成空間中資源的清理
原文鏈接:https://blog.csdn.net/qq_70793373/article/details/128989710
相關推薦
- 2022-11-03 Python?頁面解析Beautiful?Soup庫的使用方法_python
- 2022-06-02 Android實現水平帶刻度的進度條_Android
- 2023-01-05 Python?Flask?模型介紹和配置方法_python
- 2022-07-15 C#?泛型字典?Dictionary的使用詳解_C#教程
- 2022-04-11 SQL?Server的觸發器你了解多少_MsSql
- 2022-11-29 Rust?模式匹配示例詳解_Rust語言
- 2023-03-18 Python?lambda匿名函數深入講解_python
- 2022-04-22 最新版npm : 無法將“npm”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱。請檢查
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支