欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解C++中動(dòng)態(tài)內(nèi)存管理

 更新時(shí)間:2022年07月27日 16:49:51   作者:小白又菜???????  
這篇文章主要介紹了一文詳解C++中動(dòng)態(tài)內(nèi)存管理,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)孩子沒需要的朋友可以才可以參考一下

前言

在我們?nèi)粘懘a的過(guò)程中,我們對(duì)內(nèi)存空間的需求有時(shí)候在程序運(yùn)行的時(shí)候才能知道,這時(shí)候我們就需要使用動(dòng)態(tài)開辟內(nèi)存的方法。

1、C/C++程序的內(nèi)存開辟

首先我們先了解一下C/C++程序內(nèi)存分配的幾個(gè)區(qū)域:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}

  • 1. 棧區(qū)(stack):在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。 棧區(qū)主要存放運(yùn)行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回?cái)?shù)據(jù)、返回地址等。
  • 2. 堆區(qū)(heap):一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。分配方式類似于鏈表。
  • 3. 數(shù)據(jù)段(靜態(tài)區(qū))(static)存放全局變量、靜態(tài)數(shù)據(jù)。程序結(jié)束后由系統(tǒng)釋放。
  • 4. 代碼段:存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進(jìn)制代碼。

這幅圖中,我們可以發(fā)現(xiàn)普通的局部變量是在棧上分配空間的,在棧區(qū)中創(chuàng)建的變量出了作用域去就會(huì)自動(dòng)銷毀。但是被static修飾的變量是存放在數(shù)據(jù)段(靜態(tài)區(qū)),在數(shù)據(jù)段上創(chuàng)建的變量直到程序結(jié)束才銷毀,所以數(shù)據(jù)段上的數(shù)據(jù)生命周期變長(zhǎng)了。

2.C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理方式:malloc/calloc/realloc/free

在C語(yǔ)言中,我們經(jīng)常會(huì)用到malloc,calloc和realloc來(lái)進(jìn)行動(dòng)態(tài)的開辟內(nèi)存;同時(shí),C語(yǔ)言還提供了一個(gè)函數(shù)free,專門用來(lái)做動(dòng)態(tài)內(nèi)存的釋放和回收。其中他們?nèi)齻€(gè)的區(qū)別也是我們需要特別所強(qiáng)調(diào)區(qū)別的。

2.1malloc、calloc、realloc區(qū)別?

malloc函數(shù)是向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。

calloc與malloc的區(qū)別只在于calloc會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為0。

realloc函數(shù)可以做到對(duì)動(dòng)態(tài)開辟內(nèi)存大小的調(diào)整。

我們通過(guò)這三個(gè)函數(shù)的定義也可以進(jìn)行功能的區(qū)分:

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);

free(p3 );
}

3.C++內(nèi)存管理方式

我們都知道,C++語(yǔ)言是兼容C語(yǔ)言的,因此C語(yǔ)言中內(nèi)存管理方式在C++中可以繼續(xù)使用。但是有些地方就無(wú)能為力了,并且使用起來(lái)也可能比較麻煩。因此,C++擁有自己的內(nèi)管管理方式:通過(guò)new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理。

3.1 new/delete操作內(nèi)置類型

int main()
{
// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間
int* ptr1 = new int;
// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間并初始化為10
int* ptr2 = new int(10);
// 動(dòng)態(tài)申請(qǐng)3個(gè)int類型的空間(數(shù)組)
int* ptr3 = new int[3];
// 動(dòng)態(tài)申請(qǐng)3個(gè)int類型的空間,初始化第一個(gè)空間值為1
int* ptr4 = new int[3]{ 1 };
delete ptr1;
delete ptr2;
delete[] ptr3;
delete[] ptr4;
return 0;
}

  我們首先通過(guò)畫圖分析進(jìn)行剖析代碼:

我們?cè)诒O(jiān)視窗口看看這3個(gè)變量

注意:申請(qǐng)和釋放單個(gè)元素的空間,使用new和delete操作符,申請(qǐng)和釋放連續(xù)的空間,使用new[]和delete[],要匹配起來(lái)使用。

3.2 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(1);
free(p1);
delete p2;
return 0;
}

在這段代碼中,p1是我們使用malloc開辟的,p2是通過(guò)new來(lái)開辟的。我們編譯運(yùn)行這段代碼。

發(fā)現(xiàn)輸出了這兩句,那這兩句是誰(shuí)調(diào)用的呢?我們通過(guò)調(diào)試逐語(yǔ)句來(lái)分析這個(gè)過(guò)程

內(nèi)置類型區(qū)別

注意:在申請(qǐng)自定義類型的空間時(shí),new會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù),delete時(shí)會(huì)調(diào)用析構(gòu)函數(shù),而malloc和free不會(huì)。

3.3new和malloc處理失敗

int main()
{
void* p0 = malloc(1024 * 1024 * 1024);
cout << p0 << endl;

//malloc失敗,返回空指針
void* p1 = malloc(1024 * 1024 * 1024);
cout << p1 << endl;
try
{
//new失敗,拋異常
void* p2 = new char[1024 * 1024 * 1024];
cout << p2 << endl;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}

 我們能夠發(fā)現(xiàn),malloc失敗時(shí)會(huì)返回空指針,而new失敗時(shí),會(huì)拋出異常。

4.operator new與operator delete函數(shù)

4.1 operator new與operator delete函數(shù)

C++標(biāo)準(zhǔn)庫(kù)還提供了operator new和operator delete函數(shù),但是這兩個(gè)函數(shù)并不是對(duì)new和delete的重載,operator new和operator delete是兩個(gè)庫(kù)函數(shù)。(這里C++大佬設(shè)計(jì)時(shí)這樣取名確實(shí)很容易混淆)

4.1.1 我們看看operator new庫(kù)里面的源碼

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) {
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申請(qǐng)內(nèi)存失敗了,這里會(huì)拋出bad_alloc 類型異常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}

庫(kù)里面operator new的作用是封裝了malloc,如果malloc失敗,拋出異常。

4.1.2 operator delete庫(kù)里面的源碼

該函數(shù)最終是通過(guò)free來(lái)釋放空間的

//operator delete 源碼
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);
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

/*
free的實(shí)現(xiàn)
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

4.1.3 operator new和operator delete的價(jià)值(重點(diǎn))

class A {
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
//跟malloc功能一樣,失敗以后拋出異常
A* ps1 = (A*)operator new(sizeof(A));
operator delete(ps1);

A* ps2 = (A*)malloc(sizeof(A));
free(ps2);
A* ps3 = new A;
delete ps3;
return 0;
}

我們使用new的時(shí)候,new要開空間,要調(diào)用構(gòu)造函數(shù)。new可以轉(zhuǎn)換成call malloc,call 構(gòu)造函數(shù)。但是call malloc 一旦失敗,會(huì)返回空指針或者錯(cuò)誤碼。在面向?qū)ο蟮恼Z(yǔ)言中更喜歡使用異常。而operator new相比較malloc的不同就在于如果一旦失敗會(huì)拋出異常,因此new的底層實(shí)現(xiàn)是調(diào)用operator new,operator new會(huì)調(diào)用malloc(如果失敗拋出異常),再調(diào)用構(gòu)造函數(shù)。

我們通過(guò)匯編看一下ps3

operator delete同理。

總結(jié):通過(guò)上述兩個(gè)全局函數(shù)的實(shí)現(xiàn)知道,operator new 實(shí)際也是通過(guò)malloc來(lái)申請(qǐng)空間,如果malloc申請(qǐng)空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應(yīng)對(duì)措施,如果用戶提供該措施就繼續(xù)申請(qǐng),否則就拋異常。operator delete 最終是通過(guò)free來(lái)釋放空間的

4.2 重載operator new 與 operator delete(了解)

專屬的operator new技術(shù),提高效率。應(yīng)用:內(nèi)存池

class A {
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}

// 專屬的operator new
void* operator new(size_t n)
{
void* p = nullptr;
p = allocator<A>().allocate(1);
cout << "memory pool allocate" << endl;
return p;
}
void operator delete(void* p)
{
allocator<A>().deallocate((A*)p, 1);
cout << "memory pool deallocate" << endl;

}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
int n = 0;
cin >> n;
for (int i = 0; i < n; ++i)
{
A* ps1 = new A; //operator new + A的構(gòu)造函數(shù)
}
return 0;
}

注意:一般情況下不需要對(duì) operator new 和 operator delete進(jìn)行重載,除非在申請(qǐng)和釋放空間時(shí)候有某些特殊的需求。比如:在使用new和delete申請(qǐng)和釋放空間時(shí),打印一些日志信息,可以簡(jiǎn)單幫助用戶來(lái)檢測(cè)是否存在內(nèi)存泄漏。

5.new 和 delete 的實(shí)現(xiàn)原理

5.1 內(nèi)置類型

如果申請(qǐng)的是內(nèi)置類型的空間,new和malloc,delete和free基本類似,不同的地方是:new/delete申請(qǐng)和釋放的是單個(gè)元素的空間,new[]和delete[]申請(qǐng)的是連續(xù)空間,而且new在申請(qǐng)空間失敗時(shí)會(huì)拋異常,malloc會(huì)返回NULL。

5.2 自定義類型

5.2.1 new原理

  • 1、調(diào)用operator new函數(shù)申請(qǐng)空間
  • 2、再調(diào)用構(gòu)造函數(shù),完成對(duì)對(duì)象的構(gòu)造。

5.2.2 delete原理

  • 1、先調(diào)用析構(gòu)函數(shù),完成對(duì)對(duì)象中資源的清理工作。
  • 2、調(diào)用operator delete函數(shù)釋放對(duì)象的空間

5.2.3 new T[N]原理

  • 1、先調(diào)用operator new[]函數(shù),在operator new[]中世紀(jì)調(diào)用operator new函數(shù)完成N個(gè)對(duì)象空間的申請(qǐng)
  • 2、在申請(qǐng)的空間上執(zhí)行N次構(gòu)造函數(shù)

5.2.4 delete[]原理

  • 1、在釋放的對(duì)象空間上執(zhí)行N次析構(gòu)函數(shù),完成對(duì)N個(gè)對(duì)象中資源的清理
  • 2、調(diào)用operator delete[]釋放空間,實(shí)際在operator delete[]中調(diào)用operator delete來(lái)釋放空間。

6.malloc/free和new/delete的異同

6.1malloc/free和new/delete的共同點(diǎn)

都是從堆上申請(qǐng)空間,都需要用戶手動(dòng)釋放空間。

6.2malloc/free和new/delete的不同點(diǎn)

  • 1:malloc和free是函數(shù),new和delete是操作符
  • 2:malloc申請(qǐng)的空間不會(huì)初始化,new可以初始化
  • 3:malloc申請(qǐng)空間時(shí),需要手動(dòng)計(jì)算空間大小并傳遞,new只需在其后跟上空間的類型即可,如果是多個(gè)對(duì)象,[]中指定對(duì)象個(gè)數(shù)即可
  • 4:malloc的返回值為void*, 在使用時(shí)必須強(qiáng)轉(zhuǎn),new不需要,因?yàn)閚ew后跟的是空間的類型
  • 5:malloc申請(qǐng)空間失敗時(shí),返回的是NULL,因此使用時(shí)必須判空,new不需要,但是new需要捕獲異常
  • 6:申請(qǐng)自定義類型對(duì)象時(shí),malloc/free只會(huì)開辟空間,不會(huì)調(diào)用構(gòu)造函數(shù)與析構(gòu)函數(shù),而new在申請(qǐng)空間后會(huì)調(diào)用構(gòu)造函數(shù)完成對(duì)象的初始化,delete在釋放空間前會(huì)調(diào)用析構(gòu)函數(shù)完成空間中資源的清理

到此這篇關(guān)于一文詳解C++中動(dòng)態(tài)內(nèi)存管理的文章就介紹到這了,更多相關(guān)C++動(dòng)態(tài)內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 常用排序算法的C語(yǔ)言版實(shí)現(xiàn)示例整理

    常用排序算法的C語(yǔ)言版實(shí)現(xiàn)示例整理

    這篇文章主要介紹了常用排序算法的C語(yǔ)言版實(shí)現(xiàn)示例整理,包括快速排序及冒泡排序等,基本上都給出了時(shí)間復(fù)雜度,需要的朋友可以參考下
    2016-03-03
  • 詳解C++中基類與派生類的轉(zhuǎn)換以及虛基類

    詳解C++中基類與派生類的轉(zhuǎn)換以及虛基類

    這篇文章主要介紹了詳解C++中基類與派生類的轉(zhuǎn)換以及虛基類,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • Visual Studio C++指針靠前靠后的問(wèn)題全面解析

    Visual Studio C++指針靠前靠后的問(wèn)題全面解析

    這篇文章主要介紹了Visual Studio C++指針靠前靠后的問(wèn)題全面解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)

    淺析C++模板類型中的原樣轉(zhuǎn)發(fā)和可變參數(shù)的實(shí)現(xiàn)

    可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++可變參數(shù)模板的展開方式,需要的朋友可以參考下
    2022-08-08
  • c++圖像處理:24位真彩圖顏色變換實(shí)例

    c++圖像處理:24位真彩圖顏色變換實(shí)例

    下面小編就為大家?guī)?lái)一篇c++圖像處理:24位真彩圖顏色變換實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • C語(yǔ)言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    C語(yǔ)言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    這篇文章主要介紹了C語(yǔ)言中的++a和a++的區(qū)別詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C++中的編譯與鏈接

    C++中的編譯與鏈接

    這篇文章主要介紹了C++中的編譯與鏈接,編譯型語(yǔ)言SHI?c++最大的優(yōu)點(diǎn),相比于Python這種解釋型語(yǔ)言,C++在編譯階段就進(jìn)行了許多處理,在執(zhí)行階段便具有高效性,下面我們就來(lái)詳細(xì)講解該內(nèi)容吧
    2021-12-12
  • C++實(shí)現(xiàn)圖書管理系統(tǒng)源碼

    C++實(shí)現(xiàn)圖書管理系統(tǒng)源碼

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)圖書管理系統(tǒng)源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C/C++實(shí)現(xiàn)投骰子游戲

    C/C++實(shí)現(xiàn)投骰子游戲

    這篇文章主要為大家詳細(xì)介紹了C/C++實(shí)現(xiàn)投骰子游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Vs2022環(huán)境下安裝低版本.net framework的實(shí)現(xiàn)步驟

    Vs2022環(huán)境下安裝低版本.net framework的實(shí)現(xiàn)步驟

    本文主要介紹了Vs2022環(huán)境下安裝低版本.net framework的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04

最新評(píng)論