最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C++中各種不同意義的new和delete的使用

 更新時(shí)間:2022年08月14日 08:59:10   作者:林夕07  
本文主要介紹了淺談C++中各種不同意義的new和delete的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

有時(shí)候我們覺得,C++術(shù)語(yǔ)仿佛是要故意讓人難以理解似的。這里就有一個(gè)例子:請(qǐng)說明new operator 和 operator new 之間的差異。
上面這段話出自《More Effective C++》中的條款8。有興趣的讀者可以閱讀這本書?,F(xiàn)在就讓我們揭開這神秘的面紗吧。

new 到底做了什么

new是C++的一個(gè)關(guān)鍵字、操作符。
當(dāng)我們執(zhí)行Test* pt = new Test();這句代碼時(shí),實(shí)際上干了三件事情:

  • 分配內(nèi)存
  • 調(diào)用Constructor函數(shù)
  • 返回分配好的指針

為什么這么說呢?口說無(wú)憑眼見為實(shí),請(qǐng)接著往下看。

通過VS2022查看匯編代碼進(jìn)行驗(yàn)證

首先我們需要寫一個(gè)空類,然后在main中new出這個(gè)類。代碼可參考如下:

class A
{
public:
	A()
	{
		
	}
	~A()
	{
		
	}
};

int main()
{
	A* p = new A();


	delete p;
	p = nullptr;
	return 0;
}

第一步:在創(chuàng)建這一行添加斷點(diǎn)(可左擊該行行首或者在該行按F9即可)。
第二步:開始調(diào)試到當(dāng)前斷點(diǎn)處(可按F5)。
第三步:在上方功能欄中點(diǎn)擊【Debug】->【W(wǎng)indows】->【Disassembly】。中文對(duì)應(yīng)的是【調(diào)試】->【窗口】->【反匯編】。詳細(xì)請(qǐng)看下圖。

操作完上面三步之后我們就到了匯編代碼。由于重點(diǎn)不是研究匯編語(yǔ)言,所以這里我就僅對(duì)上面那三步進(jìn)行標(biāo)記。驗(yàn)證一下上面的一個(gè)猜想。

那么這里我們用到的new操作符,也就是new operator,在《C++ Primer》書中也被稱為new expression。

operator new

功能:只負(fù)責(zé)內(nèi)存分配
operator new默認(rèn)情況下調(diào)用分配內(nèi)存的代碼,去嘗試在堆區(qū)獲取一段空間,如果成功就返回,如果失敗,則調(diào)用new_hander。有關(guān)new_hander我之前寫了一篇:new_hander文章鏈接

重載類內(nèi)operator new

下面對(duì)operator new重載,進(jìn)行測(cè)試;

class A
{
public:
	A()
	{
		std::cout << "Call A Constructor!" << std::endl;
	}
	~A()
	{
		std::cout << "Call A Destructor!" << std::endl;
	}

	void* operator new(size_t size)
	{
		std::cout << "Call operator new" << "\t size = " << size << std::endl;
		return ::operator new(size); // 通過::operator new調(diào)用了全局的new
	}

};
int main()
{
	A* pt = new A();

	delete pt;
	pt = nullptr;

	return 0;
}

運(yùn)行結(jié)果:

可以看到先打印類內(nèi)的operator new再調(diào)用constructor函數(shù)最后調(diào)用destructor函數(shù)。

重載全局 ::operator new

若要重載全局的::operator new時(shí),最后就不能return 自身了需要寫成malloc(size)。對(duì)應(yīng)的delete也有delete operatoroperator delete倆種,operator delete也是可以重載的。所以一般來(lái)說重載了operator new 就需要重載對(duì)應(yīng)的operator delete了。
具體請(qǐng)看下面的代碼:

新增一個(gè)全局的operator new函數(shù)

void* operator new(size_t size)
{
	std::cout << "Call global operator new" << "\t" << size << std::endl;
	return malloc(size);
}

運(yùn)行結(jié)果:

直接調(diào)用operator new

該函數(shù)我們可以進(jìn)行重載,但是第一參數(shù)的類型必須是size_t。而且我們還可以單獨(dú)調(diào)用operator new。將返回一個(gè)void類型的指針。

在原有代碼基礎(chǔ)上,增加一個(gè)成員函數(shù)用于輸出日志。

class A
{
public:
	A()
	{
		std::cout << "Call A Constructor!" << std::endl;
	}
	~A()
	{
		std::cout << "Call A Destructor!" << std::endl;
	}

	void* operator new(size_t size)
	{
		std::cout << "Call operator new" << "\t size = " << size << std::endl;
		return ::operator new(size); // 通過::operator new調(diào)用了全局的new
	}
	void print()
	{
		std::cout << "ha ha !" << std::endl;
	}
};

void* operator new(size_t size)
{
	std::cout << "Call global operator new" << "\t size = " << size << std::endl;
	return malloc(size);
}

int main()
{
	void* rawMemory = operator new(sizeof(A));

	A* pa = static_cast<A*>(rawMemory);
	pa->print();

	delete pa;
	pa = nullptr;
	
	return 0;
}

運(yùn)行結(jié)果:

可以看到只打印了全局的operator new函數(shù)已經(jīng)析構(gòu)函數(shù)。

Placement new

頭文件:#include <new> 或者#include <new.h>
可以直接調(diào)用constructor函數(shù),是operator new的一個(gè)特殊版本,也被稱為placement new函數(shù)。

需要實(shí)現(xiàn)一個(gè)void* operator new(size_t, void* location)的重載版本。不需要申請(qǐng)內(nèi)存只需要返回當(dāng)前對(duì)象即可。
調(diào)用的語(yǔ)法:new(ObjectName) ClassName(構(gòu)造函數(shù)的參數(shù))

class A
{
public:
	A()
	{
		std::cout << "Call A Constructor!" << std::endl;
	}
	~A()
	{
		std::cout << "Call A Destructor!" << std::endl;
	}

	void* operator new(size_t size)
	{
		std::cout << "Call operator new" << "\t size = " << size << std::endl;
		return ::operator new(size); // 通過::operator new調(diào)用了全局的new
	}

	void* operator new(size_t size, void* location)
	{
		std::cout << "Call operator new(size_t size, void* location)" << std::endl;
		return location;
	}
	void print()
	{
		std::cout << "ha ha !" << std::endl;
	}
};

int main()
{
	void* rawMemory = operator new(sizeof(A));

	A* pa = static_cast<A*>(rawMemory); // 創(chuàng)建內(nèi)存

	new(pa) A(); // 調(diào)用構(gòu)造函數(shù)

	pa->print();

	delete pa;
	pa = nullptr;

	return 0;
}

運(yùn)行結(jié)果:

這里的operator new的目的是要為對(duì)象找內(nèi)存,然后返回一個(gè)指針指向它。在placement new的情況下,調(diào)用者已經(jīng)知道指向內(nèi)存的指針了,所以placement new唯一需要做的就是將已獲得指針進(jìn)行返回。雖然說size_t參數(shù)沒有用到但是必須要加,之所以不給形參名是因?yàn)榉乐咕幾g器抱怨“某某變量未被使用”。

刪除與內(nèi)存釋放

為了避免內(nèi)存泄漏,每一個(gè)動(dòng)態(tài)分配都必須匹配一個(gè)釋放動(dòng)作。
內(nèi)存釋放的動(dòng)作是由operator delete執(zhí)行,函數(shù)原型:void operator delete(void* object);

當(dāng)我們寫了這句代碼時(shí)delete pa;實(shí)際上執(zhí)行了倆件事。
1、調(diào)用destructor函數(shù)
2、釋放對(duì)象所占的內(nèi)存資源

轉(zhuǎn)換成代碼就相當(dāng)于:

	pa->~A();
	operator delete(pa);

使用operator new創(chuàng)建對(duì)象該如何釋放

當(dāng)我們?cè)趧?chuàng)建對(duì)象時(shí),沒有調(diào)用constructor函數(shù),那么釋放內(nèi)存時(shí)也不需要調(diào)用destructor函數(shù)。只需要operator delete(pa);。

int main()
{
	void* rawMemory = operator new(sizeof(A));
	
.	...其他代碼	

	operator delete(rawMemory);
	return 0;
}

上面這段代碼其實(shí)就等價(jià)于C語(yǔ)言里面調(diào)用malloc和free函數(shù)。

使用placement new創(chuàng)建對(duì)象時(shí)該如何釋放

如果使用placement new在內(nèi)存中產(chǎn)生對(duì)象,我們不能使用delete operator,因?yàn)闀?huì)調(diào)用operator delete函數(shù)來(lái)釋放內(nèi)存。首先該內(nèi)存并不是由該對(duì)象的operator new函數(shù)分配而來(lái)。它僅僅做了一個(gè)返回而已,所以這種情況下只需要調(diào)用destructor函數(shù)即可。

int main()
{
	void* rawMemory = operator new(sizeof(A));
	

	A* pa = static_cast<A*>(rawMemory); // 創(chuàng)建內(nèi)存

	new(pa)A(); // 調(diào)用構(gòu)造函數(shù)

	pa->~A();
	pa = nullptr;

	operator delete(rawMemory);
	return 0;
}

在上面這段代碼中,pa對(duì)象就是使用placement new,所以最后只需要調(diào)用destructor函數(shù)。

針對(duì)數(shù)組的創(chuàng)建和釋放

當(dāng)我們使用A* pa = new A[10];這段代碼時(shí),分配內(nèi)存的方式將會(huì)發(fā)生變化。
1、由operator new 改為 operator new[],也被叫為array new。同樣array new也可以被重載,
2、array new必須調(diào)用數(shù)組中的每個(gè)對(duì)象的constructor函數(shù)。上面那個(gè)例子就會(huì)調(diào)用10個(gè)A的無(wú)參構(gòu)造函數(shù)。
3、array new在釋放內(nèi)存時(shí)。上面那個(gè)例子就會(huì)調(diào)用10個(gè)A的destructor函數(shù)。
4、該類必須有無(wú)參構(gòu)造函數(shù)。

所以我們同樣也可以修改operator new[]所調(diào)用的 new operator函數(shù),以及delete[] operator。

系統(tǒng)維護(hù)開銷

在面對(duì)數(shù)組時(shí),new 會(huì)額外分配空間來(lái)存儲(chǔ)new的長(zhǎng)度(一般為一個(gè)指針大小,32位平臺(tái)下4字節(jié),64位平臺(tái)下8字節(jié))。這個(gè)叫系統(tǒng)維護(hù)開銷。
下面是測(cè)試代碼,類A是個(gè)空類只占一個(gè)字節(jié),正常來(lái)說應(yīng)該申請(qǐng)10個(gè)字節(jié)的內(nèi)存。

int main()
{
	A* pa = new A[10];


	delete[] pa;
	return 0;
}

32位環(huán)境下:

64位環(huán)境下:

可以看到對(duì)申請(qǐng)了一個(gè)指針的內(nèi)存用來(lái)存放申請(qǐng)對(duì)象的個(gè)數(shù)。

總結(jié)

下面針對(duì)new的三種使用方式做了一個(gè)使用場(chǎng)景總結(jié),切記操作對(duì)應(yīng)的new 時(shí)還需要對(duì)應(yīng)的delete。
1、需要將對(duì)象創(chuàng)建在堆區(qū),那么就使用 new operator 也就是new操作符。它會(huì)幫你分配內(nèi)存并調(diào)用constructor函數(shù)。
2、僅需要分配內(nèi)存,那么就使用operator new,這樣就不會(huì)調(diào)用constructor函數(shù)。
3、需要在堆區(qū)創(chuàng)建對(duì)象時(shí)自定義內(nèi)存分配方式,那么就需要重寫operator new函數(shù)然后使用new operator即可。
4、需要在已分配的內(nèi)存中調(diào)用構(gòu)造函數(shù),那么就使用placement new。

到此這篇關(guān)于淺談C++中各種不同意義的new和delete的使用的文章就介紹到這了,更多相關(guān)C++ new和delete 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Visual Studio2000系列版本安裝OpenGL的圖文教程

    Visual Studio2000系列版本安裝OpenGL的圖文教程

    這篇文章主要介紹了Visual Studio2000系列版本安裝OpenGL的圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 詳解C++17中的decltype類型推導(dǎo)

    詳解C++17中的decltype類型推導(dǎo)

    這篇文章主要介紹了C++17中的decltype類型推導(dǎo),本文從泛型編程中經(jīng)常會(huì)遇到2個(gè)常見問題入手,循序漸進(jìn)的分析了從C++11開始引入的關(guān)鍵字decltype,需要的朋友可以參考下
    2023-06-06
  • C語(yǔ)言實(shí)例梳理講解常用關(guān)鍵字的用法

    C語(yǔ)言實(shí)例梳理講解常用關(guān)鍵字的用法

    關(guān)鍵字是C語(yǔ)言非常重要的一部分,熟練的掌握和使用關(guān)鍵字有助于我們更加熟悉了解C語(yǔ)言,同時(shí)C語(yǔ)言的關(guān)鍵字也是面試筆試中??嫉膬?nèi)容。C語(yǔ)言的關(guān)鍵字共有32個(gè),但并不是每個(gè)關(guān)鍵字都有坑,本篇文章將通過理論聯(lián)系實(shí)際的方式為大家講解C語(yǔ)言中易混易錯(cuò)以及??嫉囊恍╆P(guān)鍵字
    2022-05-05
  • C語(yǔ)言實(shí)現(xiàn)的順序表功能完整實(shí)例

    C語(yǔ)言實(shí)現(xiàn)的順序表功能完整實(shí)例

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)的順序表功能,結(jié)合完整實(shí)例形式分析了C語(yǔ)言順序表的創(chuàng)建、添加、刪除、排序、合并等相關(guān)操作技巧,需要的朋友可以參考下
    2018-04-04
  • C++基于文件流與armadillo讀取mnist示例詳解

    C++基于文件流與armadillo讀取mnist示例詳解

    這篇文章主要給大家介紹了關(guān)于C++基于文件流與armadillo讀取mnist的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • c語(yǔ)言常見圖片格式判斷實(shí)例

    c語(yǔ)言常見圖片格式判斷實(shí)例

    這篇文章介紹了c語(yǔ)言常見圖片格式判斷實(shí)例,有需要的朋友可以參考一下
    2013-09-09
  • C語(yǔ)言與Lua之間的相互調(diào)用詳解

    C語(yǔ)言與Lua之間的相互調(diào)用詳解

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言與Lua之間的相互調(diào)用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中數(shù)制轉(zhuǎn)換實(shí)例代碼

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中數(shù)制轉(zhuǎn)換實(shí)例代碼

    這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中數(shù)制轉(zhuǎn)換實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • C語(yǔ)言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建

    C語(yǔ)言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建

    這篇文章主要介紹了C語(yǔ)言之實(shí)現(xiàn)棧的基礎(chǔ)創(chuàng)建,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++類中const修飾的成員函數(shù)及日期類小練習(xí)

    C++類中const修飾的成員函數(shù)及日期類小練習(xí)

    將const修飾的“成員函數(shù)”稱之為const成員函數(shù),const修飾類成員函數(shù),表明在該成員函數(shù)中不能對(duì)類的任何成員進(jìn)行修改,下面這篇文章主要給大家介紹了關(guān)于C++類中const修飾的成員函數(shù)及日期類小練習(xí)?的相關(guān)資料,需要的朋友可以參考下
    2023-01-01

最新評(píng)論

平昌县| 双辽市| 米泉市| 东方市| 汝城县| 翼城县| 拜城县| 五台县| 云浮市| 丰镇市| 武安市| 长海县| 大丰市| 唐山市| 三穗县| 巴林左旗| 井冈山市| 长岛县| 麦盖提县| 莱州市| 靖宇县| 白沙| 邵东县| 任丘市| 宁陕县| 西平县| 瑞金市| 吉首市| 瓮安县| 濮阳市| 彰化市| 石林| 德州市| 宁河县| 郴州市| 永胜县| 宜川县| 阳山县| 三江| 广河县| 鄯善县|