🎈個人主頁:🎈 :???初階牛???
🐻推薦專欄1: 🍔🍟🌯C語言初階
🐻推薦專欄2: 🍔🍟🌯C語言進階
🔑個人信條: 🌵知行合一
🍉本篇簡介:>:講解C++中的有關內存管理知識,如何new出對象?
金句分享:
?如果事與愿違,請相信另有安排.?
前言
講解C++
中有關new
的知識,與malloc
進行對比,以及深入探索new
的實現原理.
目錄
- 前言
- 一、malloc和new的使用
- 1.1 new創建內置類型(int等)
- 1.2 new創建數組
- 1.3 創建對象
- 1.4 異常處理
- 二、malloc和new的區別:(面試熱門)
- 三、new和delete的深層解密
- 3.1 解密實現原理
- 3.2 通過匯編指令驗證
一、malloc和new的使用
在C
語言階段,我們習慣使用malloc
向內存申請空間,但是在C++
階段,我們習慣用new
在動態內存中創建對象,為什么呢?
1.1 new創建內置類型(int等)
在創建內置類型時,new
只是不需要進行強轉和計算內置類型的大小,看起來更加簡潔,方便.
//malloc申請內置類型int* p1 = (int*)malloc(sizeof(int));free(p1);//new對比int* ptr1 = new int;delete ptr1;
1.2 new創建數組
new + 對象的類型 + [個數] + (初始化的值)
new + 對象的類型 + [個數] + {num1,num2,…}
需要注意的是,連續的多個空間須使用new[]
與delete[]
搭配
//申請數組int* p3 = (int*)malloc(sizeof(int) * 10);//賦值for (int i = 0; i < 10; i++){p3[i] = i;}//打印for (int i = 0; i < 10; i++){cout << p3[i] << " ";}cout << endl;// new創建數組int* ptr3 = new int[10]{0,1,2,3,4,5,6,7,8,9};for (int i = 0; i < 10; i++){cout << ptr3[i] << " ";}//釋放free(p3);delete[] ptr3;
1.3 創建對象
如何使用new
進行創建對象?
#include <iostream>
using namespace std;
#include<stdlib.h>class Date
{
public:Date():_year(2020),_month(6),_day(6){cout << "A()" << endl;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){cout << "~A()" << endl;free(_a);}
private:int _year;int _month;int _day;int* _a=nullptr;
};int main()
{//malloc出對象Date* d1 = (Date*)malloc(sizeof(Date));d1->print();free(d1);//new出對象Date* d2 = new Date;d2->print();delete d2;return 0;
}
運行結果:
-842150451–842150451–842150451
A()
2020-6-6
~A()
通過上段代碼我們發現,malloc
只是進行開空間的操作,對象并沒有得到初始化操作.
new
則是在開空間的同時,會調用對象的構造函數,將對象進行初始化.
free
只是進行簡單的釋放申請的空間,如果對象中存在動態申請的成員,則無法進行釋放.
delete
會在釋放申請的對象空間的同時,調用對象的析構函數,徹底的完成空間的清理工作.
1.4 異常處理
對于malloc
函數,當malloc
申請內存空間失敗的時候,會返回一個NULL
指針.
我們通常通過判斷返回值是否為NULL
來判斷是否申請成功.
int* a = (int*)malloc(10000* sizeof(int));if (a == NULL){perror("malloc a fail");//申請失敗時,打印錯誤信息return 0;}
new失敗不會返回NULL,而是通過拋出異常.
在C++
中,可以使用try-catch
語句來捕獲new
操作符拋出的異常。new
操作符在內存分配過程中如果失敗,會拋出一個bad_alloc
異常。
示例代碼:
try {int* myArray = new int[10000]; // 分配一個包含10000個整數的數組// ...delete[] myArray;
}
catch (const std::bad_alloc& e) {// 處理內存分配失敗的異常std::cout << "內存分配失敗: " << e.what() << std::endl;
}
在上述代碼中,new
操作符用于分配一個包含10000
個整數的數組。如果內存分配失敗,將拋出一個bad_alloc
異常。catch
語句塊接收這個異常,并執行相應的處理代碼。在這個示例中,異常被捕獲后會打印一條錯誤消息。
需要注意的是,catch
語句塊中的參數類型應為const std::bad_alloc&
,因為bad_alloc
是標準異常類,它派生自std::exception
,通常以常量引用的形式傳遞給異常處理代碼。
二、malloc和new的區別:(面試熱門)
在C++
中,malloc
和new
都用于在堆上分配內存,但有一些重要的區別。
-
語法和類型安全性:
malloc
和free
是函數,new
和delete
是操作符
(1)malloc
是C語言中的函數,malloc
需要指定要分配的內存大小,并返回一個指向未初始化內存塊的指針。
(2)new
是C++
中的運算符。new
可以直接在創建對象時進行初始化,并返回一個指向已經構造的對象的指針。new
操作符會執行類型檢查,確保分配的內存與對象類型匹配。 -
構造函數和析構函數調用:
(1)使用new
分配內存時,會自動調用對象的構造函數進行初始化。
(2)使用malloc
分配內存時,不會調用對象的構造函數,需要手動調用構造函數初始化對象。
(3)同樣,使用delete
釋放new
分配的內存時,會自動調用析構函數進行清理工作。而使用free
釋放malloc
分配的內存時,不會自動調用析構函數,需要手動執行清理操作。 -
內存大小計算:
(1)使用malloc
分配內存時,需要顯式指定要分配的內存塊的大小,以字節為單位。
(2)使用new
分配單個對象時,編譯器會自動計算所需的內存大小,以對象的類型為基礎。對于數組對象,需要使用new[]
和delete[]
,同樣會自動計算所需的內存。 -
異常處理:
new
在分配內存失敗時,會拋出std::bad_alloc
異常,而malloc
在分配內存失敗時,返回NULL
指針。 -
malloc
的返回值為void*
, 在使用時必須強轉,new
不需要,因為new
后跟的是空間的類型
總的來說,new
相對于malloc
提供了更高級的、更安全的內存分配方式,能夠自動調用構造函數和析構函數,執行類型檢查,并提供異常處理。因此,在C++
中,推薦使用new
和delete
來進行動態內存分配和釋放。如果你需要使用C語言的庫或與C代碼進行交互,可以使用malloc
和free
。
三、new和delete的深層解密
3.1 解密實現原理
學到這里,我們知道new會代用構造函數,還會拋出異常,那它究竟是怎么實現的呢?
operator new
的實現
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)//通過mallo開空間if (_callnewh(size) == 0){// report no memory// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}
看不懂沒關系,只需要知道operator delete
調用了free
函數即可
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 );//調用了free函數__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn;
}
free
的實現就是一個宏定義_free_dbg(p, _NORMAL_BLOCK)
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
我們可以直接調用operator new
和operator delete
函數.
void test1()
{A* a1 = (A*)operator new (sizeof(A));A* a2 = (A*)malloc (sizeof(A));operator delete(a1);free(a2);
}
int main()
{test1();return 0;
}
發現operator new
的使用和malloc
沒什么區別,
只是一個拋異常.
一個返回NULL
.
3.2 通過匯編指令驗證
void test1()
{A* a1 = new A;delete a1;
}
通過調試窗口的反匯編窗口,我們查看A* a1 = new A;
對應的匯編指令:
會發現,new
操作符果然是調用operator new
+構造函數.
查看delete
操作符,由于vs
編譯器進行了再封裝,我們需要進到下面這條指令里面去看:
不難發現,delete
操作符=調用析構函數+調用operator delete
函數
好的,本篇有關new
操作符和delete
操作符的相關知識就講到這里了,希望對大家有所幫助.
如果覺得文章有幫助的話,可以來個一鍵三連嗎?