免費做網(wǎng)站軟件下載關鍵詞搜索網(wǎng)站
目錄
1. 一圖搞懂C/C++的內存分布
2. 存在動態(tài)內存分配的原因
3. C語言中的動態(tài)內存管理方式
4.?C++內存管理方式
4.1 new/delete操作內置類型
4.2 new/delete操作自定義類型
1. 一圖搞懂C/C++的內存分布
說明:
1. 棧區(qū)(stack):在執(zhí)行函數(shù)時,函數(shù)內局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結 束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是 分配的內存容量有限。 棧區(qū)主要存放運行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返回地址等。
2. 堆區(qū)(heap):一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。分配方式類似于鏈表。
3. 數(shù)據(jù)段(靜態(tài)區(qū)):(static)存放全局變量、靜態(tài)數(shù)據(jù)。程序結束后由系統(tǒng)釋放。
4. 代碼區(qū):存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進制代碼。
2. 存在動態(tài)內存分配的原因
現(xiàn)在我們最朗朗上手的內存開辟方式有:
int a = 10;//在??臻g上開辟4個字節(jié)的空間int arr[100] = { 0 };//在??臻g上開辟100×4個字節(jié)的空間
上述兩種方法開辟空間的方式有兩個特點:
1. 空間開辟大小是固定的;
2. 數(shù)組在申明的時候,必須指定數(shù)組的長度,它所需要的內存在編譯時分配。
但是對于空間的需求,不僅僅是上述的情況。有時我們需要的空間大小在程序運行時才能知道。
其如果比我們開辟的空間大,程序會不會報錯呢?如果比我們開辟的空間小,那又會不會造成內存浪費,降低運行效率呢?
所以這種靜態(tài)的內存開辟方式就不能滿足我們的需求了,那該如何來解決呢?
這時動態(tài)的內存開辟或許就可以滿足我們的需求。
3. C語言中的動態(tài)內存管理方式
C語言中的動態(tài)內存管理方式為malloc、calloc、realloc、free函數(shù)的使用,具體請看:詳解C/C++動態(tài)內存函數(shù)(malloc、free、calloc、realloc)
4.?C++內存管理方式
我們說過,C++是兼容C語言的,所以C語言的內存管理方式在C++中可以繼續(xù)使用,但有些地方就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內存管理方式:通過new和delete操作符進行動態(tài)內存管理。
了解C++的類與對象之后,我們知道了內置類型和自定義類型,我們似乎可以發(fā)現(xiàn),在學習了C++的很多知識后,好像很大一部分篇幅都在介紹處理自定義類型的情況,這些也恰巧可以體現(xiàn)C++面向對象的原因,所以,對于new和delete我們也應該分為內置類型與自定義類型來討論。
4.1 new/delete操作內置類型
new/delete操作內置類型與malloc、calloc、realloc、free函數(shù)除了用法上,其他方面沒有任何區(qū)別,用法也完全可以照貓畫虎,不過確實new/delete更為方便:
void test()
{// ①動態(tài)申請一個int類型的空間//malloc//int* ptr1 = (int*)malloc(sizeof(int));//newint* ptr1 = new int;// ②動態(tài)申請一個int類型的空間并初始化為10//malloc/*int* ptr2 = (int*)malloc(sizeof(int));if (ptr2 == NULL){perror("malloc");exit(-1);}*ptr2 = 10;*///newint* ptr2 = new int(10);//③ 動態(tài)申請10個int類型的空間//calloc/*int* ptr3 = (int*)calloc(10, sizeof(int));if (ptr3 == NULL){perror("calloc");exit(-1);}*///newint* ptr3 = new int[10];//④動態(tài)申請10個int類型的空間,并初始化成1~10//直接演示new:int* ptr4 = new int[10]{ 1,2,3,4,5,6,7,8,9,10 };//(如果未初始化完全,其余默認初始化為0)//free/*free(ptr1);ptr1 = NULL;*///deletedelete ptr1;delete ptr2;delete[] ptr3;delete[] ptr4;
}
(注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續(xù)的空間,使用 new[]和delete[],要匹配起來使用。)
4.2 new/delete操作自定義類型
我們已經(jīng)說了,new/delete與malloc、calloc、realloc、free除了用法上,其他方面沒有區(qū)別,那既然已經(jīng)有了后者,為什么還要再引入new/delete呢?僅僅是為了用法上更方便一些嗎?
答案當然不是的,沒有任何區(qū)別僅僅是針對內置類型來說的,我們在學習操作符重載時就發(fā)現(xiàn),+、-、*、/ 這些運算符對于自定義類型并不能直接拿來用,需要加以重載我們才可以使用。
malloc、calloc、realloc、free這些函數(shù)也是同樣的道理,所以針對自定義類型,new與delete就應運而生了。
那么,我們就跟著new/delete操作內置類型的用法照貓畫虎,來試一下自定義類型A:
#include <iostream>
using namespace std;class A
{
public://構造函數(shù)A(int a = 0):_a(a){cout << "調用了構造函數(shù) " << this << endl;}//析構函數(shù)~A(){cout << "調用了析構函數(shù) " << this << endl;}private:int _a;
};int main()
{//動態(tài)申請1個A類型的空間并初始化為1A* a1 = new A(1);delete a1;return 0;
}
運行結果:
從運行結果來看:
new/delete 和 malloc/free最大區(qū)別是 new/delete對于【自定義類型】除了開空間還會調用構造函數(shù)和析構函數(shù)。
所以我們可以說:
new的本質:開空間+調用構造函數(shù)初始化;
delete的本質:調用析構函數(shù)+釋放空間。
另外,熟悉一下用new對自定義類型開多個空間:
int main()
{//動態(tài)申請3個A類型的空間并初始化為1~3//方法①:有名對象/*A a1(1);A a2(2);A a3(3);A* aa1 = new A[3]{ a1,a2,a3 };delete[] aa1;*///方法②:匿名對象A* aa2 = new A[3]{ A(1),A(2),A(3) };delete[] aa2;//方法③:巧用構造函數(shù)的隱式類型轉換A* aa3 = new A[3]{ 1,2,3 };delete[] aa3;return 0;
}
(本篇完)