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

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

 更新時(shí)間:2022年07月20日 16:30:58   作者:玄鳥軒墨???????  
這篇文章主要介紹了C++ 動(dòng)態(tài)內(nèi)存管理詳情解說,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下,希望對(duì)你的學(xué)習(xí)有所幫助

寫在前面

我們知道C++是支持C語言的,也就是說,C語言里面的malloc等函數(shù)都可以在C++中使用,但是C++有支持了另外兩個(gè)關(guān)鍵字,這是很有用的,我們需要看看C++的動(dòng)態(tài)內(nèi)存.

C/C++ 內(nèi)存分布

我記得,在初識(shí)C語言那里就和大家分享了程序虛擬地址空間的概念,無論是C語言的nalloc函數(shù),還是我們現(xiàn)在要分享的new,都是在堆區(qū)開辟空間,這一點(diǎn)是我們要首先記得的。

C語言內(nèi)存管理方式

C語言是通過函數(shù)來經(jīng)行動(dòng)態(tài)的內(nèi)存開辟的,標(biāo)準(zhǔn)庫(kù)里面提供三個(gè)函數(shù),這里我就不加贅述了,大家應(yīng)該都是知道的。我么看看用法就可以了。

#include <stdio.h>
#include <assert.h>

int main()
{
// malloc 開辟空間 不初始化
int* p1 = (int*)malloc(sizeof(int)* 4);
assert(p1);

//calloc 開辟空間 初始化 為 0
int* p2 = (int*)calloc(4, sizeof(int));
assert(p2);
// 追加 空間
p1 = (int*)relloc(p1, sizeof(int)* 8);

free(p1);
free(p2);
return 0;
}

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

C++是支持C語言的,也是說C++是可以使用這些函數(shù)的,但是除了這些函數(shù)外,C++有增加了new和delete這個(gè)兩個(gè)關(guān)鍵字,分別對(duì)標(biāo)的malloc/calloc和free,而且C++的方式比C的好用.

C++為何增加了new 和 delete

我們都知道,C語言的結(jié)構(gòu)體里面不支持函數(shù),所以大佬們提出了類的概念,出現(xiàn)了class,又害怕自己有時(shí)后可能忘記初始化和清除掉內(nèi)存,就出現(xiàn)了構(gòu)造函數(shù)和析構(gòu)函數(shù),讓編譯器自動(dòng)調(diào)用,可以說,所有的事物的出現(xiàn)都是為了我們更好的使用語言,new和delete也似乎如此,C語言的動(dòng)態(tài)內(nèi)存開辟是有一定的麻煩的,而且對(duì)于自動(dòng)類型很不友好,后面我們就會(huì)比較他們的優(yōu)劣.

我們還發(fā)現(xiàn)一個(gè)很直接問題,每一次開辟空間我們都要強(qiáng)制類型轉(zhuǎn)換,而且還需要判斷內(nèi)存是不是究竟開出來了,這也太麻煩了,new卻不會(huì)出現(xiàn)這種事,如果沒有開辟出,編譯器會(huì)拋異常,我們就不需要再自己手動(dòng)檢測(cè)了.

new 一個(gè)對(duì)象

這樣,我先和大家演示內(nèi)置類型,自定義類型那里我準(zhǔn)備專門和malloc比較一下.

#include <iostream>
using namespace std;

int main()
{
int* p1 = new int;
*p1 = 10;
cout << *p1 << endl;
return 0;
}

我們也知道,再C++中,內(nèi)置類行也被作為類了,我們可以再new的時(shí)候?qū)λM(jìn)行初始化.

int main()
{
int* p = new int(0);
cout << *p << endl;

return 0;
}

new 一個(gè)數(shù)組

new一個(gè)數(shù)組更是簡(jiǎn)單,我們直接寫出來就可以了.

int main()
{
int* p = new int[10]; // new 一個(gè) 10 個(gè)int 類行的空間
return 0;
}

我們也可以在new空間的時(shí)候進(jìn)行實(shí)例化,不過要顯示實(shí)例化

int main()
{
int* p = new int[10]{1,2,3};
return 0;
}

delete

大家可能發(fā)現(xiàn),我上面都沒有釋放空間,這會(huì)造成內(nèi)存泄漏,這里我們用另一個(gè)關(guān)鍵字delete,這里就比較簡(jiǎn)單了.

大家可能疑惑delete[],這里我們記住就可以了,如果你要清除數(shù)組的空間,最好使用這種方式,或許對(duì)于內(nèi)置類行,使用delete也可以,但是對(duì)于自定義類行可能會(huì)報(bào)錯(cuò),這里我也放在后面談.

int main()
{
int* p1 = new int;
int* p2 = new int[10]{1,2,3};
delete p1;
delete[] p2;
return 0;
}

malloc & new

我們需要對(duì)比一下malloc和new它們之間的區(qū)別,這樣就可以知道C++為何這么喜歡new了.

內(nèi)置類型

我們先下一個(gè)結(jié)論,它們兩個(gè)對(duì)于內(nèi)置類行除了報(bào)錯(cuò)之外是沒有任何區(qū)別的,都不會(huì)經(jīng)行初始化,這里我們現(xiàn)不談報(bào)錯(cuò)的信息,異常和沒有和大家分享.

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

int* p2 = (int*)malloc(sizeof(int)* 10);
assert(p2);

delete[] p1;
free(p2);
return 0;
}

自定義類型

對(duì)于自定義類型,它們的差別可大了去了.

我們先來準(zhǔn)備一個(gè)類:

class A
{
public:
A(int a = 0,int b=0)
:_a(a)
, _b(b)
{
cout << "構(gòu)造函數(shù)" << endl;
}
~A()
{
cout << "析構(gòu)函數(shù)" << endl;
}
private:
int _a;
int _b;
};

malloc是直接開辟空間,對(duì)于里面的構(gòu)造函數(shù)是不會(huì)調(diào)用的,free的時(shí)候也不會(huì)調(diào)用析構(gòu)函數(shù)

int main()
{
A* aa = (A*)malloc(sizeof(A));
free(aa);
return 0;
}

new 和 delete會(huì)分別調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù),完成初始化

int main()
{
A* aa = new A;
delete aa;
return 0;
}

operator new與operator delete函數(shù)

這里一看像是new和delete的重載,記住,這不是,就是名字有點(diǎn)奇怪罷了.這是C++里面的全局函數(shù),它的使用方法和malloc一樣,而且作用也是有一樣的,不會(huì)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù).

new和delete是用戶進(jìn)行動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的操作符,operator new 和operator delete是系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請(qǐng)空間,delete在底層通過operator delete全局函數(shù)來釋放空間

int main()
{
A* aa = (A*)operator new(sizeof(A));
operator delete (aa);
return 0;
}

原理

通過源碼我們就會(huì)發(fā)現(xiàn),實(shí)際上operator new與operator delete函數(shù) 本質(zhì)上是malloc和free的封裝,就是報(bào)錯(cuò)的信息有點(diǎn)不同,封裝的報(bào)錯(cuò)的信息是異常.

operator new 的原理是 malloc

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); }

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); // 注意 C語言的free 就是這個(gè)函數(shù) __FINALLY _munlock(_HEAP_LOCK); /* release other threads */ __END_TRY_FINALLY return; }

為何出現(xiàn)這兩個(gè)函數(shù)

這兩個(gè)函數(shù)不是給我們調(diào)用的,是為了new的底層調(diào)用的,我們new一個(gè)對(duì)象,就相當(dāng)于call operator new 和 call 對(duì)象的構(gòu)造函數(shù),這才是它們出現(xiàn)的原因.

大家可以看看反匯編.

delete & delete[]

這個(gè)我們可以這么理解,對(duì)于內(nèi)置類型,它們就沒必要討論的,作用差不多.但是對(duì)于自定義類型就有很大的問題.

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

大家先看看結(jié)果:

delete[] 析構(gòu)相應(yīng)的的次數(shù)

int main() { A* aa = new A[3]; delete[] aa; return 0; }

delete 析構(gòu)一次,還會(huì)報(bào)錯(cuò)

int main() { A* aa = new A[3]; delete aa; return 0; }

內(nèi)存池

這里我想提一個(gè)概念,我們都知道m(xù)alloc和new都是在堆上開辟空間,如果我們要是多次的去開辟空間,效率是不是有點(diǎn)慢,想一想,我們一次開辟一次,開了個(gè)上千次,每次都要去申請(qǐng),我們?cè)谙?,能不能單?dú)的劃分出一塊區(qū)域,專門提供我們想要的對(duì)象來開辟空間,這就是內(nèi)存池最初的想法,大家可能會(huì)感到疑惑,內(nèi)存池和堆有什么不同嗎,簡(jiǎn)單來說,內(nèi)存池離你近,可以提高效率。我們可以這么類比,堆就像每噸你在學(xué)校吃飯就和你老爸要錢,每頓都要,那么內(nèi)存池就像月初你直接和你爸要好這個(gè)月的生活費(fèi),一月要一次,肯定是后者的效率比較高的。

那么我們?cè)撊绾问褂脙?nèi)存池,標(biāo)準(zhǔn)庫(kù)里面也提供了一個(gè),這里我們需要在類內(nèi)重寫operator new與operator delete函數(shù)函數(shù),大家先來了解一下用法就可以了,我們先不來細(xì)究,后面可能會(huì)有一個(gè)高并發(fā)內(nèi)存池的項(xiàng)目要和大家分享,不過這個(gè)時(shí)間就有點(diǎn)長(zhǎng)了。

struct ListNode
{
ListNode* _next;
ListNode* _prev;
int _data;

// 申請(qǐng)空間的是后去內(nèi)存 池
void* operator new(size_t n)
{
void* p = nullptr;
p = allocator<ListNode>().allocate(1);
cout << "memory pool allocate" << endl;
return p;
}
void operator delete(void* p)
{
allocator<ListNode>().deallocate((ListNode*)p, 1);
cout << "memory pool deallocate" << endl;
}
};
class List
{
public:
List()
{
_head = new ListNode;
_head->_next = _head;
_head->_prev = _head;
}
~List()
{
ListNode* cur = _head->_next;
while (cur != _head)
{
ListNode* next = cur->_next;
delete cur;
cur = next;
}
delete _head;
_head = nullptr;
}
private:
ListNode* _head;
};

int main()
{
List l1;
return 0;
}

定位 new

我們已經(jīng)知道了,使用operator new開辟出的空間是不會(huì)初始化的,而且現(xiàn)在我們是無法通過對(duì)象來顯式調(diào)用構(gòu)造函數(shù)的,這也就意味著我們要是向修改成員變量,一定會(huì)破壞封裝.但是C++這里也提供了一個(gè)定位new的技術(shù)可以幫助我們?cè)俅螌?shí)例化,我們先來看看用法.

class A
{
public:
A(int a = 0)
:_a(a)
{
}
private:
int _a;
};

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

// 定位 new
new(a)A (1);
return 0;
}

從這里我們就可以知道了,定位new有下面兩種用法

  • new(要初始化的指針) 指針解引用對(duì)應(yīng)的類行 直接調(diào)用默認(rèn)構(gòu)造函數(shù)
  • new(要初始化的指針) 指針解引用對(duì)應(yīng)的類行 (構(gòu)造函數(shù)要傳的參數(shù)) 調(diào)用相應(yīng)的構(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)文章

  • Linux C 時(shí)間函數(shù)應(yīng)用

    Linux C 時(shí)間函數(shù)應(yīng)用

    本文是關(guān)于Linux C時(shí)間函數(shù) time_t struct tm 進(jìn)行了詳細(xì)的分析介紹并有應(yīng)用實(shí)例,希望能幫到有需要的同學(xué)
    2016-07-07
  • C++ push_back()函數(shù)使用詳解

    C++ push_back()函數(shù)使用詳解

    這篇文章主要介紹了C++ push_back()函數(shù)使用詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Qt中QStringList與QString的常用方法總結(jié)

    Qt中QStringList與QString的常用方法總結(jié)

    這篇文章主要為大家總結(jié)了Qt中QString 與 (QStringList | QByteArray)之間的轉(zhuǎn)換,以及QString、QStringList的一些常用方法,感興趣的可以收藏一下
    2022-12-12
  • C++樹之遍歷二叉樹實(shí)例詳解

    C++樹之遍歷二叉樹實(shí)例詳解

    這篇文章主要給大家介紹了關(guān)于C++樹之遍歷二叉樹的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C++ Boost Chrono實(shí)現(xiàn)計(jì)時(shí)碼表流程詳解

    C++ Boost Chrono實(shí)現(xiàn)計(jì)時(shí)碼表流程詳解

    Boost是為C++語言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱
    2022-11-11
  • C語言如何求整數(shù)的位數(shù)及各位數(shù)字之和

    C語言如何求整數(shù)的位數(shù)及各位數(shù)字之和

    這篇文章主要介紹了C語言如何求整數(shù)的位數(shù)及各位數(shù)字之和,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++?棧和隊(duì)列的實(shí)現(xiàn)超詳細(xì)解析

    C++?棧和隊(duì)列的實(shí)現(xiàn)超詳細(xì)解析

    棧和隊(duì)列,嚴(yán)格意義上來說,也屬于線性表,因?yàn)樗鼈円捕加糜诖鎯?chǔ)邏輯關(guān)系為?"一對(duì)一"?的數(shù)據(jù),但由于它們比較特殊,因此將其單獨(dú)作為一章,做重點(diǎn)講解
    2022-03-03
  • C++中spdlog的簡(jiǎn)單使用示例

    C++中spdlog的簡(jiǎn)單使用示例

    spdlog是一個(gè)開源、跨平臺(tái)、無依賴、只有頭文件的C++11日志庫(kù),所以這篇文章主要來和大家介紹一下一個(gè)簡(jiǎn)單的spdlog使用示例,感興趣的小伙伴可以了解一下
    2023-08-08
  • C++的STL中accumulate函數(shù)的使用方法

    C++的STL中accumulate函數(shù)的使用方法

    這篇文章主要介紹了C++的STL中accumulate的使用方法,accumulate作用是累加求和即自定義類型數(shù)據(jù)處理,下文具體的操作方法需要的小伙伴可以參考一下
    2022-03-03
  • 使用C語言打印月歷

    使用C語言打印月歷

    這篇文章主要為大家詳細(xì)介紹了使用C語言打印月歷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06

最新評(píng)論