今天來分享C++動態內存管理相關知識,閑言勿談,直接上干貨。
1. 動態內存的開辟和銷毀(new和delete)
(1)前置知識:我們知道c語言有malloc和calloc和realloc三個函數可以進行動態的開辟內存,那么它們有什么區別呢?首先是malloc,malloc表示直接在堆上動態開辟內存空間,返回void*,而calloc不僅可以直接在堆上動態開辟內存空間,還會把開辟空間的內容初始化為0,calloc返回的也是void*,realloc是在原有的空間的基礎上進行擴容,也是返回void*.c語言雖然有三個動態開辟內存的函數,但在某些場景下不適用,同時用起來也比較麻煩,所以c++引入了一個new操作符進行動態開辟內存,delete操作符進行銷毀開辟的內存,那么接下來我們看看new的用法吧。
(2)new和delete用法
new和delete操作符對內置類型進行開辟空間
new和malloc對于內置類型開辟空間,功能都差不多。
int main()
{//表示在堆上申請一個int空間int* p1 = new int;delete p1;//表示在堆上申請一個int空間并初始化為4int* p2 = new int(4);delete p2;//表示在堆上申請3個int空間int* p3 = new int[3];delete[] p3;return 0;
}
new和delete操作符對自定義類型進行開辟空間
我們來看看new和malloc對于自定義類型開辟空間的不同之處。
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};int main()
{A* p1 = (A*)malloc(sizeof(A));A* p2 = new A;free(p1);delete p2;return 0;
}
我們來看看這個代碼運行的結果
咋出現了調用構造函數和析構函數呢?是誰調用的呢?
我們把malloc和free的函數進行注釋掉,如果還調用構造函數和析構函數,那么證明是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* p1 = (A*)malloc(sizeof(A));*/A* p2 = new A;//free(p1);delete p2;return 0;
}
還是調用了構造函數和析構函數,現在我們就清楚了malloc函數和new操作符,free函數和delete操作符之間的區別是,new開辟空間是會調用構造函數進行初始化,delete在釋放空間是會調用析構函數對對象中的資源進行清理。
(2)operator new函數和operator delete函數
我們先來看看c++標準庫里面是如何實現operator new和operator delete函數的。
我們可以看到operator new和operator delete是依靠malloc和free函數實現的,該函數實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間失敗,嘗試執行空間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否則拋異常。
new和delete實現的原理
(1)對于內置類型,new和malloc功能相似,delete和free功能相似。
(1)對于自定義類型
new不僅調用operator new函數開辟空間還會調用構造函數。
delete不僅會調用operator delete函數釋放空間,還會調用析構函數完成對對象資源的清理工作
總結:
1.共同點:malloc和new都是在堆上開辟空間,都需要手動釋放開辟的空間
2.不同點:malloc和free是函數,new和delete是操作符(概念性質不同)
malloc開辟空間是要傳需要開辟的字節數,返回的是void*;而new后跟申請對象的類型,返回的是申
請對象的類型的指針
new會調用構造函數,開辟失敗會拋異常,malloc開辟失敗會返回0