<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們知道C++是支援C語言的,也就是說,C語言裡面的malloc等函數都可以在C++中使用,但是C++有支援了另外兩個關鍵字,這是很有用的,我們需要看看C++的動態記憶體.
我記得,在初識C語言那裡就和大家分享了程式虛擬地址空間的概念,無論是C語言的nalloc函數,還是我們現在要分享的new,都是在堆區開闢空間,這一點是我們要首先記得的。
C語言是通過函數來經行動態的記憶體開闢的,標準庫裡面提供三個函數,這裡我就不加贅述了,大家應該都是知道的。我麼看看用法就可以了。
#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++是支援C語言的,也是說C++是可以使用這些函數的,但是除了這些函數外,C++有增加了new和delete這個兩個關鍵字,分別對標的malloc/calloc和free,而且C++的方式比C的好用.
我們都知道,C語言的結構體裡面不支援函數,所以大佬們提出了類的概念,出現了class,又害怕自己有時後可能忘記初始化和清除掉記憶體,就出現了建構函式和解構函式,讓編譯器自動呼叫,可以說,所有的事物的出現都是為了我們更好的使用語言,new和delete也似乎如此,C語言的動態記憶體開闢是有一定的麻煩的,而且對於自動型別很不友好,後面我們就會比較他們的優劣.
我們還發現一個很直接問題,每一次開闢空間我們都要強制型別轉換,而且還需要判斷記憶體是不是究竟開出來了,這也太麻煩了,new卻不會出現這種事,如果沒有開闢出,編譯器會拋異常,我們就不需要再自己手動檢測了.
這樣,我先和大家演示內建型別,自定義型別那裡我準備專門和malloc比較一下.
#include <iostream> using namespace std; int main() { int* p1 = new int; *p1 = 10; cout << *p1 << endl; return 0; }
我們也知道,再C++中,內建類行也被作為類了,我們可以再new的時候對它進行初始化.
int main() { int* p = new int(0); cout << *p << endl; return 0; }
new一個陣列更是簡單,我們直接寫出來就可以了.
int main() { int* p = new int[10]; // new 一個 10 個int 類行的空間 return 0; }
我們也可以在new空間的時候進行範例化,不過要顯示範例化
int main() { int* p = new int[10]{1,2,3}; return 0; }
大家可能發現,我上面都沒有釋放空間,這會造成記憶體漏失,這裡我們用另一個關鍵字delete,這裡就比較簡單了.
大家可能疑惑delete[],這裡我們記住就可以了,如果你要清除陣列的空間,最好使用這種方式,或許對於內建類行,使用delete也可以,但是對於自定義類行可能會報錯,這裡我也放在後面談.
int main() { int* p1 = new int; int* p2 = new int[10]{1,2,3}; delete p1; delete[] p2; return 0; }
我們需要對比一下malloc和new它們之間的區別,這樣就可以知道C++為何這麼喜歡new了.
我們先下一個結論,它們兩個對於內建類行除了報錯之外是沒有任何區別的,都不會經行初始化,這裡我們現不談報錯的資訊,異常和沒有和大家分享.
int main() { int* p1 = new int[10]; int* p2 = (int*)malloc(sizeof(int)* 10); assert(p2); delete[] p1; free(p2); return 0; }
對於自定義型別,它們的差別可大了去了.
我們先來準備一個類:
class A { public: A(int a = 0,int b=0) :_a(a) , _b(b) { cout << "建構函式" << endl; } ~A() { cout << "解構函式" << endl; } private: int _a; int _b; };
malloc是直接開闢空間,對於裡面的建構函式是不會呼叫的,free的時候也不會呼叫解構函式
int main() { A* aa = (A*)malloc(sizeof(A)); free(aa); return 0; }
new 和 delete會分別呼叫建構函式和解構函式,完成初始化
int main() { A* aa = new A; delete aa; return 0; }
這裡一看像是new和delete的過載,記住,這不是,就是名字有點奇怪罷了.這是C++裡面的全域性函數,它的使用方法和malloc一樣,而且作用也是有一樣的,不會呼叫建構函式和解構函式.
new和delete是使用者進行動態記憶體申請和釋放的操作符,operator new 和operator delete是系統提供的全域性函數,new在底層呼叫operator new全域性函數來申請空間,delete在底層通過operator delete全域性函數來釋放空間
int main() { A* aa = (A*)operator new(sizeof(A)); operator delete (aa); return 0; }
通過原始碼我們就會發現,實際上operator new與operator delete函數 本質上是malloc和free的封裝,就是報錯的資訊有點不同,封裝的報錯的資訊是異常.
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 // 如果申請記憶體失敗了,這裡會丟擲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 就是這個函數 __FINALLY _munlock(_HEAP_LOCK); /* release other threads */ __END_TRY_FINALLY return; }
這兩個函數不是給我們呼叫的,是為了new的底層呼叫的,我們new一個物件,就相當於call operator new 和 call 物件的建構函式,這才是它們出現的原因.
大家可以看看反組合.
這個我們可以這麼理解,對於內建型別,它們就沒必要討論的,作用差不多.但是對於自定義型別就有很大的問題.
大家先看看結果:
delete[] 解構相應的的次數
int main() { A* aa = new A[3]; delete[] aa; return 0; }
delete 解構一次,還會報錯
int main() { A* aa = new A[3]; delete aa; return 0; }
這裡我想提一個概念,我們都知道malloc和new都是在堆上開闢空間,如果我們要是多次的去開闢空間,效率是不是有點慢,想一想,我們一次開闢一次,開了個上千次,每次都要去申請,我們在想,能不能單獨的劃分出一塊區域,專門提供我們想要的物件來開闢空間,這就是記憶體池最初的想法,大家可能會感到疑惑,記憶體池和堆有什麼不同嗎,簡單來說,記憶體池離你近,可以提高效率。我們可以這麼類比,堆就像每噸你在學校吃飯就和你老爸要錢,每頓都要,那麼記憶體池就像月初你直接和你爸要好這個月的生活費,一月要一次,肯定是後者的效率比較高的。
那麼我們該如何使用記憶體池,標準庫裡面也提供了一個,這裡我們需要在類內重寫operator new與operator delete函數函數,大家先來了解一下用法就可以了,我們先不來細究,後面可能會有一個高並行記憶體池的專案要和大家分享,不過這個時間就有點長了。
struct ListNode { ListNode* _next; ListNode* _prev; int _data; // 申請空間的是後去記憶體 池 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; }
我們已經知道了,使用operator new開闢出的空間是不會初始化的,而且現在我們是無法通過物件來顯式呼叫建構函式的,這也就意味著我們要是向修改成員變數,一定會破壞封裝.但是C++這裡也提供了一個定位new的技術可以幫助我們再次範例化,我們先來看看用法.
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有下面兩種用法
到此這篇關於C++ 動態記憶體管理詳情解說的文章就介紹到這了,更多相關C++ 動態記憶體管理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45