www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 公眾號精選 > C語言與CPP編程
[導讀]C語言內(nèi)存管理指對系統(tǒng)內(nèi)存的分配、創(chuàng)建、使用這一系列操作。在內(nèi)存管理中,由于是操作系統(tǒng)內(nèi)存,使用不當會造成畢竟麻煩的結果。本文將從系統(tǒng)內(nèi)存的分配、創(chuàng)建出發(fā),并且使用例子來舉例說明內(nèi)存管理不當會出現(xiàn)的情況及解決辦法。

C 語言內(nèi)存管理指對系統(tǒng)內(nèi)存的分配、創(chuàng)建、使用這一系列操作。在內(nèi)存管理中,由于是操作系統(tǒng)內(nèi)存,使用不當會造成畢竟麻煩的結果。本文將從系統(tǒng)內(nèi)存的分配、創(chuàng)建出發(fā),并且使用例子來舉例說明內(nèi)存管理不當會出現(xiàn)的情況及解決辦法。

一、內(nèi)存

在計算機中,每個應用程序之間的內(nèi)存是相互獨立的,通常情況下應用程序 A 并不能訪問應用程序 B,當然一些特殊技巧可以訪問,但此文并不詳細進行說明。例如在計算機中,一個視頻播放程序與一個瀏覽器程序,它們的內(nèi)存并不能訪問,每個程序所擁有的內(nèi)存是分區(qū)進行管理的。

在計算機系統(tǒng)中,運行程序 A 將會在內(nèi)存中開辟程序 A 的內(nèi)存區(qū)域 1,運行程序 B 將會在內(nèi)存中開辟程序 B 的內(nèi)存區(qū)域 2,內(nèi)存區(qū)域 1 與內(nèi)存區(qū)域 2 之間邏輯分隔。

1.1 內(nèi)存四區(qū)

在程序 A 開辟的內(nèi)存區(qū)域 1 會被分為幾個區(qū)域,這就是內(nèi)存四區(qū),內(nèi)存四區(qū)分為棧區(qū)、堆區(qū)、數(shù)據(jù)區(qū)與代碼區(qū)。

棧區(qū)指的是存儲一些臨時變量的區(qū)域,臨時變量包括了局部變量、返回值、參數(shù)、返回地址等,當這些變量超出了當前作用域時將會自動彈出。該棧的最大存儲是有大小的,該值固定,超過該大小將會造成棧溢出。

堆區(qū)指的是一個比較大的內(nèi)存空間,主要用于對動態(tài)內(nèi)存的分配;在程序開發(fā)中一般是開發(fā)人員進行分配與釋放,若在程序結束時都未釋放,系統(tǒng)將會自動進行回收。

數(shù)據(jù)區(qū)指的是主要存放全局變量、常量和靜態(tài)變量的區(qū)域,數(shù)據(jù)區(qū)又可以進行劃分,分為全局區(qū)與靜態(tài)區(qū)。全局變量與靜態(tài)變量將會存放至該區(qū)域。

代碼區(qū)就比較好理解了,主要是存儲可執(zhí)行代碼,該區(qū)域的屬性是只讀的。

1.2 使用代碼證實內(nèi)存四區(qū)的底層結構

由于棧區(qū)與堆區(qū)的底層結構比較直觀的表現(xiàn),在此使用代碼只演示這兩個概念。首先查看代碼觀察棧區(qū)的內(nèi)存地址分配情況:

#include
int?main()
{
?int?a?=?0;
?int?b?=?0;
?char?c='0';
?printf("變量a的地址是:%d\n變量b的地址是:%d\n變量c的地址是:%d\n",?&a,?&b,?&c);

}

運行結果為:

我們可以觀察到變量 a 的地址是 2293324 變量 b 的地址是 2293320,由于 int 的數(shù)據(jù)大小為 4 所以兩者之間間隔為 4;再查看變量 c,我們發(fā)現(xiàn)變量 c 的地址為 2293319,與變量 b 的地址 2293324 間隔 1,因為 c 的數(shù)據(jù)類型為 char,類型大小為 1。在此我們觀察發(fā)現(xiàn),明明我創(chuàng)建變量的時候順序是 a 到 b 再到 c,為什么它們之間的地址不是增加而是減少呢?那是因為棧區(qū)的一種數(shù)據(jù)存儲結構為先進后出,如圖:

首先棧的頂部為地址的“最小”索引,隨后往下依次增大,但是由于堆棧的特殊存儲結構,我們將變量 a 先進行存儲,那么它的一個索引地址將會是最大的,隨后依次減少;第二次存儲的值是 b,該值的地址索引比 a 小,由于 int 的數(shù)據(jù)大小為 4,所以在 a 地址為 2293324 的基礎上往上減少 4 為 2293320,在存儲 c 的時候為 char,大小為 1,則地址為 2293319。由于 a、b、c 三個變量同屬于一個棧內(nèi),所以它們地址的索引是連續(xù)性的,那如果我創(chuàng)建一個靜態(tài)變量將會如何?在以上內(nèi)容中說明了靜態(tài)變量存儲在靜態(tài)區(qū)內(nèi),我們現(xiàn)在就來證實一下:

#include
int?main()
{
?
?int?a?=?0;
?int?b?=?0;
?char?c='0';
?static?int?d?=?0;
?
?printf("變量a的地址是:%d\n變量b的地址是:%d\n變量c的地址是:%d\n",?&a,?&b,?&c);
?
?printf("靜態(tài)變量d的地址是:%d\n",?&d);

}

運行結果如下:

以上代碼中創(chuàng)建了一個變量 d,變量 d 為靜態(tài)變量,運行代碼后從結果上得知,靜態(tài)變量 d 的地址與一般變量 a、b、c 的地址并不存在連續(xù),他們兩個的內(nèi)存地址是分開的。那接下來在此建一個全局變量,通過上述內(nèi)容得知,全局變量與靜態(tài)變量都應該存儲在靜態(tài)區(qū),代碼如下:

#include
int?e?=?0;
int?main()
{
?
?int?a?=?0;
?int?b?=?0;
?char?c='0';
?static?int?d?=?0;
?
?printf("變量a的地址是:%d\n變量b的地址是:%d\n變量c的地址是:%d\n",?&a,?&b,?&c);
?
?printf("靜態(tài)變量d的地址是:%d\n",?&d);
?printf("全局變量e的地址是:%d\n",?&e);

}

運行結果如下:

從以上運行結果中證實了上述內(nèi)容的真實性,并且也得到了一個知識點,棧區(qū)、數(shù)據(jù)區(qū)都是使用棧結構對數(shù)據(jù)進行存儲。

在以上內(nèi)容中還說明了一點棧的特性,就是容量具有固定大小,超過最大容量將會造成棧溢出。查看如下代碼:

#include

int?main()
{
?char?arr_char[1024*1000000];
????arr_char[0]?=?'0';
}

以上代碼定義了一個字符數(shù)組 arr_char,并且設置了大小為 1024*1000000,設置該數(shù)據(jù)是方便查看大??;隨后在數(shù)組頭部進行賦值。運行結果如下:

這是程序運行出錯,原因是造成了棧的溢出。在平常開發(fā)中若需要大容量的內(nèi)存,需要使用堆。

堆并沒有棧一樣的結構,也沒有棧一樣的先進后出。需要人為的對內(nèi)存進行分配使用。代碼如下:

#include
#include
#include?
int?main()
{
?char?*p1?=?(char?*)malloc(1024*1000000);
?strcpy(p1,?"這里是堆區(qū)");
?printf("%s\n",?p1);
}

以上代碼中使用了strcpy 往手動開辟的內(nèi)存空間 p1 中傳數(shù)據(jù)“這里是堆區(qū)”,手動開辟空間使用 malloc,傳入申請開辟的空間大小 1024*1000000,在棧中那么大的空間必定會造成棧溢出,而堆本身就是大容量,則不會出現(xiàn)該情況。隨后輸出開辟的內(nèi)存中內(nèi)容,運行結果如下:

在此要注意p1是表示開辟的內(nèi)存空間地址。

二、malloc 和 free

在 C 語言(不是 C++)中,malloc 和 free 是系統(tǒng)提供的函數(shù),成對使用,用于從堆中分配和釋放內(nèi)存。malloc 的全稱是 memory allocation 譯為“動態(tài)內(nèi)存分配”。

2.1 malloc 和 free 的使用

在開辟堆空間時我們使用的函數(shù)為 malloc,malloc 在 C 語言中是用于申請內(nèi)存空間,malloc 函數(shù)的原型如下:

void?*malloc(size_t?size);

在 malloc 函數(shù)中,size 是表示需要申請的內(nèi)存空間大小,申請成功將會返回該內(nèi)存空間的地址;申請失敗則會返回 NULL,并且申請成功也不會自動進行初始化。

細心的同學可能會發(fā)現(xiàn),該函數(shù)的返回值說明為 void *,在這里 void * 并不指代某一種特定的類型,而是說明該類型不確定,通過接收的指針變量從而進行類型的轉換。在分配內(nèi)存時需要注意,即時在程序關閉時系統(tǒng)會自動回收該手動申請的內(nèi)存 ,但也要進行手動的釋放,保證內(nèi)存能夠在不需要時返回至堆空間,使內(nèi)存能夠合理的分配使用。

釋放空間使用 free 函數(shù),函數(shù)原型如下:

void?free(void?*ptr);

free 函數(shù)的返回值為 void,沒有返回值,接收的參數(shù)為使用 malloc 分配的內(nèi)存空間指針。一個完整的堆內(nèi)存申請與釋放的例子如下:

#include
#include
#include?

int?main()?{
????int?n,?*p,?i;
????printf("請輸入一個任意長度的數(shù)字來分配空間:");
????scanf("%d",?&n);
????
????p?=?(int?*)malloc(n?*?sizeof(int));
?if(p==NULL){
??printf("申請失敗\n");
??return?0;
?}else{
??printf("申請成功\n");
?}?
?
?memset(p,?0,?n?*?sizeof(int));//填充0?
?
?//查看?
????for?(i?=?0;?i?????????printf("%d?",?p[i]);
????printf("\n");

????free(p);
????p?=?NULL;
????return?0;
}

以上代碼中使用了 malloc 創(chuàng)建了一個由用戶輸入創(chuàng)建指定大小的內(nèi)存,判斷了內(nèi)存地址是否創(chuàng)建成功,且使用了 memset 函數(shù)對該內(nèi)存空間進行了填充值,隨后使用 for 循環(huán)進行了查看。最后使用了 free 釋放了內(nèi)存,并且將 p 賦值 NULL,這點需要主要,不能使指針指向未知的地址,要置于 NULL;否則在之后的開發(fā)者會誤以為是個正常的指針,就有可能再通過指針去訪問一些操作,但是在這時該指針已經(jīng)無用,指向的內(nèi)存也不知此時被如何使用,這時若出現(xiàn)意外將會造成無法預估的后果,甚至導致系統(tǒng)崩潰,在 malloc 的使用中更需要需要。

2.2 內(nèi)存泄漏與安全使用實例與講解

內(nèi)存泄漏是指在動態(tài)分配的內(nèi)存中,并沒有釋放內(nèi)存或者一些原因造成了內(nèi)存無法釋放,輕度則造成系統(tǒng)的內(nèi)存資源浪費,嚴重的導致整個系統(tǒng)崩潰等情況的發(fā)生。

內(nèi)存泄漏通常比較隱蔽,且少量的內(nèi)存泄漏發(fā)生不一定會發(fā)生無法承受的后果,但由于該錯誤的積累將會造成整體系統(tǒng)的性能下降或系統(tǒng)崩潰。特別是在較為大型的系統(tǒng)中,如何有效的防止內(nèi)存泄漏等問題的出現(xiàn)變得尤為重要。例如一些長時間的程序,若在運行之初有少量的內(nèi)存泄漏的問題產(chǎn)生可能并未呈現(xiàn),但隨著運行時間的增長、系統(tǒng)業(yè)務處理的增加將會累積出現(xiàn)內(nèi)存泄漏這種情況;這時極大的會造成不可預知的后果,如整個系統(tǒng)的崩潰,造成的損失將會難以承受。由此防止內(nèi)存泄漏對于底層開發(fā)人員來說尤為重要。

C 程序員在開發(fā)過程中,不可避免的面對內(nèi)存操作的問題,特別是頻繁的申請動態(tài)內(nèi)存時會及其容易造成內(nèi)存泄漏事故的發(fā)生。如申請了一塊內(nèi)存空間后,未初始化便讀其中的內(nèi)容、間接申請動態(tài)內(nèi)存但并沒有進行釋放、釋放完一塊動態(tài)申請的內(nèi)存后繼續(xù)引用該內(nèi)存內(nèi)容;如上所述這種問題都是出現(xiàn)內(nèi)存泄漏的原因,往往這些原因由于過于隱蔽在測試時不一定會完全清楚,將會導致在項目上線后的長時間運行下,導致災難性的后果發(fā)生。

如下是一個在子函數(shù)中進行了內(nèi)存空間的申請,但是并未對其進行釋放:

#include
#include
#include?
void?m()?{?
?char?*p1;?
?p1?=?malloc(100);?
?printf("開始對內(nèi)存進行泄漏...");
}
?
int?main()?{
????m();
????return?0;
}

如上代碼中,使用 malloc 申請了 100 個單位的內(nèi)存空間后,并沒有進行釋放。假設該 m 函數(shù)在當前系統(tǒng)中調(diào)用頻繁,那將會每次使用都將會造成 100 個單位的內(nèi)存空間不會釋放,久而久之就會造成嚴重的后果。理應在 p1 使用完畢后添加 free 進行釋放:

free(p1);

以下示范一個讀取文件時不規(guī)范的操作:

#include
#include
#include?
int?m(char?*filename)?{?
?FILE*?f;
?int?key;?
?f?=?fopen(filename,?"r");?
?fscanf(f,?"%d",?&key);?
?return?key;?
}
?
int?main()?{
????m("number.txt");
????return?0;
}

以上文件在讀取時并沒有進行 fclose,這時將會產(chǎn)生多余的內(nèi)存,可能一次還好,多次會增加成倍的內(nèi)存,可以使用循環(huán)進行調(diào)用,之后在任務管理器中可查看該程序運行時所占的內(nèi)存大小,代碼為:

#include
#include
#include?
int?m(char?*filename)?{?
?FILE*?f;
?int?key;?
?f?=?fopen(filename,?"r");?
?fscanf(f,?"%d",?&key);?
?return?key;?
}
?
int?main()?{
?int?i;
?for(i=0;i<500;i++)?{
?????m("number.txt");
?}
????return?0;
}

可查看添加循環(huán)后的程序與添加循環(huán)前的程序做內(nèi)存占用的對比,就可以發(fā)現(xiàn)兩者之間添加了循環(huán)的代碼將會成本增加占用容量。

未被初始化的指針也會有可能造成內(nèi)存泄漏的情況,因為指針未初始化所指向不可控,如:

int?*p;
*p?=?val;

包括錯誤的釋放內(nèi)存空間:

pp=p;
free(p);?
free(pp);

釋放后使用,產(chǎn)生懸空指針。在申請了動態(tài)內(nèi)存后,使用指針指向了該內(nèi)存,使用完畢后我們通過 free 函數(shù)釋放了申請的內(nèi)存,該內(nèi)存將會允許其它程序進行申請;但是我們使用過后的動態(tài)內(nèi)存指針依舊指向著該地址,假設其它程序下一秒申請了該區(qū)域內(nèi)的內(nèi)存地址,并且進行了操作。當我依舊使用已 free 釋放后的指針進行下一步的操作時,或者所進行了一個計算,那么將會造成的結果天差地別,或者是其它災難性后果。所以對于這些指針在生存期結束之后也要置為 null。查看一個示例,由于 free 釋放后依舊使用該指針,造成的計算結果天差地別:

#include
#include
#include?
int?m(char?*freep)?{?
?int?val=freep[0];
?printf("2*freep=:%d\n",val*2);
?free(freep);
?val=freep[0];
?printf("2*freep=:%d\n",val*2);
}
?
int?main()?{
?int?*freep?=?(int?*)?malloc(sizeof?(int));
?freep[0]=1;
?m(freep);
????return?0;
????
}

以上代碼使用 malloc 申請了一個內(nèi)存后,傳值為 1;在函數(shù)中首先使用 val 值接收 freep 的值,將 val 乘 2,之后釋放 free,重新賦值給 val,最后使用 val 再次乘 2,此時造成的結果出現(xiàn)了極大的改變,而且最恐怖的是該錯誤很難發(fā)現(xiàn),隱蔽性很強,但是造成的后顧難以承受。運行結果如下:

三、 new 和 delete

C++ 中使用 new 和 delete 從堆中分配和釋放內(nèi)存,new 和 delete 是運算符,不是函數(shù),兩者成對使用(后面說明為什么成對使用)。

new/delete 除了分配內(nèi)存和釋放內(nèi)存(與 malloc/free),還做更多的事情,所有在 C++ 中不再使用 malloc/free 而使用 new/delete。

3.1 new 和 delete 使用

new 一般使用格式如下:

  • 指針變量名 = new 類型標識符;
  • 指針變量名 = new 類型標識符(初始值);
  • 指針變量名 = new 類型標識符[內(nèi)存單元個數(shù)];

在C++中new的三種用法包括:plain new, nothrow new 和 placement new。

plain new 就是我們最常使用的 new 的方式,在 C++ 中的定義如下:

void*?operator?new(std::size_t)?throw(std::bad_alloc);??
void?operator?delete(?void?*)?throw();

plain new 在分配失敗的情況下,拋出異常 std::bad_alloc 而不是返回 NULL,因此通過判斷返回值是否為 NULL 是徒勞的。

char?*getMemory(unsigned?long?size)???
{????
????char?*?p?=?new?char[size];???
????return?p;?
}???
void?main(void)???
{
????try{???
????????char?*?p?=?getMemory(1000000);????//?可能發(fā)生異常
????????//?...???
????????delete?[]?p;???
????}???
????catch(const?std::bad_alloc?&?ex)???
????{
????????cout?<<?ex.what();
????}???
}

nothrow new 是不拋出異常的運算符new的形式。nothrow new在失敗時,返回NULL。定義如下:

void?*?operator?new(std::size_t,?const?std::nothrow_t&)?throw();
void?operator?delete(void*)?throw();
void?func(unsinged?long?length)???
{
????unsinged?char?*?p?=?new(nothrow)?unsinged?char[length];???
????//?在使用這種new時要加(nothrow)?,表示不使用異常處理?。
?
????if?(p?==?NULL)??//?不拋異常,一定要檢查
????????cout?<"allocte?failed?!";???
????????//?...???
????delete?[]?p;
}

placement new 意即“放置”,這種new允許在一塊已經(jīng)分配成功的內(nèi)存上重新構造對象或?qū)ο髷?shù)組。placement new不用擔心內(nèi)存分配失敗,因為它根本不分配內(nèi)存,它做的唯一一件事情就是調(diào)用對象的構造函數(shù)。定義如下:

void*?operator?new(size_t,?void*);
void?operator?delete(void*,?void*);

palcement new 的主要用途就是反復使用一塊較大的動態(tài)分配的內(nèi)存來構造不同類型的對象或者他們的數(shù)組。placement new構造起來的對象或其數(shù)組,要顯示的調(diào)用他們的析構函數(shù)來銷毀,千萬不要使用delete。

void?main()???
{??
????using?namespace?std;???
????char?*?p?=?new(nothrow)?char?[4];???
????if?(p?==?NULL)???
????{
????????cout?<"allocte?failed"?<????????exit(?-1?);
????}???
????//?...???
????long?*?q?=?new?(p)?long(1000);???
??? delete []p;????//?只釋放 p,不要用q釋放。
}

p 和 q 僅僅是首址相同,所構建的對象可以類型不同。所“放置”的空間應小于原空間,以防不測。當”放置new”超過了申請的范圍,Debug 版下會崩潰,但 Release 能運行而不會出現(xiàn)崩潰!

該運算符的作用是:只要第一次分配成功,不再擔心分配失敗。

void?main()???
{
????using?namespace?std;???
????char?*?p?=?new(nothrow)?char?[100];???
????if?(p?==?NULL)???
????{??
????????cout?<"allocte?failed"?<????????exit(-1);
????}???
????long?*?q1?=?new?(p)?long(100);???
????//?使用q1??...???
????int?*?q2?=?new?(p)?int[100/sizeof(int)];???
????//?使用q2?...???
????ADT?*?q3?=?new?(p)?ADT[100/sizeof(ADT)];???
????//?使用q3??然后釋放對象?...???
??? delete [] p;????//?只釋放空間,不再析構對象。
}

注意:使用該運算符構造的對象或數(shù)組,一定要顯式調(diào)用析構函數(shù),不可用 delete 代替析構,因為 placement new 的對象的大小不再與原空間相同。

void?main()???
{??
????using?namespace?std;???
????char?*?p?=?new(nothrow)?char?[sizeof(ADT)+2];???
????if?(p?==?NULL)???
????{??
????????cout?<"allocte?failed"?<<?endl;
????????exit(-1);?
????}?
????//?...?
????ADT?*?q?=?new?(p)?ADT;?
????//?...?
????//?delete?q;?//?錯誤
????q->ADT::~ADT();??//?顯式調(diào)用析構函數(shù),僅釋放對象
????delete?[]?p;?????//?最后,再用原指針來釋放內(nèi)存
}

placement new 的主要用途就是可以反復使用一塊已申請成功的內(nèi)存空間。這樣可以避免申請失敗的徒勞,又可以避免使用后的釋放。

特別要注意的是對于 placement new 絕不可以調(diào)用的 delete, 因為該 new 只是使用別人替它申請的地方。釋放內(nèi)存是 nothrow new 的事,即要使用原來的指針釋放內(nèi)存。free/delete 不要重復調(diào)用,被系統(tǒng)立即回收后再利用,再一次 free/delete 很可能把不是自己的內(nèi)存釋放掉,導致異常甚至崩潰。

上面提到 new/delete 比 malloc/free 多做了一些事情,new 相對于 malloc 會額外的做一些初始化工作,delete 相對于 free 多做一些清理工作。

class?A
{
?public:
?????A()
?????{
????????cont<<"A()構造函數(shù)被調(diào)用"<?????}
?????~A()
?????{
????????cont<<"~A()構造函數(shù)被調(diào)用"<?????}
}

在 main 主函數(shù)中,加入如下代碼:

A*?pa?=?new?A();??//類?A?的構造函數(shù)被調(diào)用
delete?pa;????????//類?A?的析構函數(shù)被調(diào)用

可以看出:使用 new 生成一個類對象時系統(tǒng)會調(diào)用該類的構造函數(shù),使用 delete 刪除一個類對象時,系統(tǒng)會調(diào)用該類的析構函數(shù)??梢哉{(diào)用構造函數(shù)/析構函數(shù)就意味著 new 和 delete 具備針對堆所分配的內(nèi)存進行初始化和釋放的能力,而 malloc 和 free 不具備。

2.2 delete 與 delete[] 的區(qū)別

c++ 中對 new 申請的內(nèi)存的釋放方式有 delete 和 delete[] 兩種方式,到底這兩者有什么區(qū)別呢?

我們通常從教科書上看到這樣的說明:

  • delete 釋放 new 分配的單個對象指針指向的內(nèi)存
  • delete[] 釋放 new 分配的對象數(shù)組指針指向的內(nèi)存 那么,按照教科書的理解,我們看下下面的代碼:
int?*a?=?new?int[10];
delete?a;????????//方式1
delete[]?a;?????//方式2
  1. 針對簡單類型 使用 new 分配后的不管是數(shù)組還是非數(shù)組形式內(nèi)存空間用兩種方式均可 如:
int?*a?=?new?int[10];
delete?a;
delete[]?a;

此種情況中的釋放效果相同,原因在于:分配簡單類型內(nèi)存時,內(nèi)存大小已經(jīng)確定,系統(tǒng)可以記憶并且進行管理,在析構時,系統(tǒng)并不會調(diào)用析構函數(shù)。

它直接通過指針可以獲取實際分配的內(nèi)存空間,哪怕是一個數(shù)組內(nèi)存空間(在分配過程中 系統(tǒng)會記錄分配內(nèi)存的大小等信息,此信息保存在結構體 _CrtMemBlockHeader 中,具體情況可參看 VC 安裝目錄下 CRTSRCDBGDEL.cpp)。

  1. 針對類 Class,兩種方式體現(xiàn)出具體差異

當你通過下列方式分配一個類對象數(shù)組:

class?A
???{
????private:
??????char?*m_cBuffer;
??????int?m_nLen;

???``?public:
??????A(){?m_cBuffer?=?new?char[m_nLen];?}
??????~A()?{?delete?[]?m_cBuffer;?}
???};

???A?*a?=?new?A[10];
???delete?a;?????????//僅釋放了a指針指向的全部內(nèi)存空間?但是只調(diào)用了a[0]對象的析構函數(shù)?剩下的從a[1]到a[9]這9個用戶自行分配的m_cBuffer對應內(nèi)存空間將不能釋放?從而造成內(nèi)存泄漏
???delete[]?a;??????//調(diào)用使用類對象的析構函數(shù)釋放用戶自己分配內(nèi)存空間并且???釋放了a指針指向的全部內(nèi)存空間

所以總結下就是,如果 ptr 代表一個用new申請的內(nèi)存返回的內(nèi)存空間地址,即所謂的指針,那么:

delete ptr ?代表用來釋放內(nèi)存,且只用來釋放 ptr 指向的內(nèi)存。delete[] rg ? 用來釋放rg指向的內(nèi)存,!!還逐一調(diào)用數(shù)組中每個對象的destructor??!

對于像 int/char/long/int*/struct 等等簡單數(shù)據(jù)類型,由于對象沒有 destructor ,所以用 delete 和 delete []是一樣的!但是如果是 C++ 對象數(shù)組就不同了!

關于 new[] 和 delete[],其中又分為兩種情況:

  • (1) 為基本數(shù)據(jù)類型分配和回收空間;
  • (2) 為自定義類型分配和回收空間;

對于 (1),上面提供的程序已經(jīng)證明了 delete[] 和 delete 是等同的。但是對于 (2),情況就發(fā)生了變化。

我們來看下面的例子,通過例子的學習了解 C++ 中的 delete 和 delete[] 的使用方法

#include?
using?namespace?std;

class?Babe
{
public:
????Babe()
????{
????????cout?<????}

????~Babe()
????{
????????cout?<'t?Go?away,listen?to?me\"?<????}
};

int?main()
{
????Babe*?pbabe?=?new?Babe[3];
????delete?pbabe;
????pbabe?=?new?Babe[3];
????delete[]?pbabe;
????return?0;
}

結果是:

Create?a?babe?to?talk?with?me
Create?a?babe?to?talk?with?me
Create?a?babe?to?talk?with?me
Babe?don\'t?go?away,listen?to?me
Create?a?babe?to?talk?with?me
Create?a?babe?to?talk?with?me
Create?a?babe?to?talk?with?me
Babe?don\'
t?go?away,listen?to?me
Babe?don\'t?go?away,listen?to?me
Babe?don\'
t?go?away,listen?to?me

大家都看到了,只使用 delete 的時候只出現(xiàn)一個 Babe don’t go away,listen to me,而使用 delete[] 的時候出現(xiàn) 3 個 Babe don’t go away,listen to me。不過不管使用 delete 還是 delete[] 那三個對象的在內(nèi)存中都被刪除,既存儲位置都標記為可寫,但是使用 delete 的時候只調(diào)用了 pbabe[0] 的析構函數(shù),而使用了 delete[] 則調(diào)用了 3 個 Babe 對象的析構函數(shù)。

你一定會問,反正不管怎樣都是把存儲空間釋放了,有什么區(qū)別。

答:關鍵在于調(diào)用析構函數(shù)上。此程序的類沒有使用操作系統(tǒng)的系統(tǒng)資源(比如:Socket、File、Thread等),所以不會造成明顯惡果。如果你的類使用了操作系統(tǒng)資源,單純把類的對象從內(nèi)存中刪除是不妥當?shù)?,因為沒有調(diào)用對象的析構函數(shù)會導致系統(tǒng)資源不被釋放,這些資源的釋放必須依靠這些類的析構函數(shù)。所以,在用這些類生成對象數(shù)組的時候,用 delete[] 來釋放它們才是王道。而用 delete 來釋放也許不會出問題,也許后果很嚴重,具體要看類的代碼了。

最后祝各位保持良好的代碼編寫規(guī)范降低嚴重錯誤的產(chǎn)生。

免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉