C++中delete與delete[]


這篇文章是CSDN C++論壇中多次討論到的一個問題。

先看下面程序:

#include <iostream>
using namespace std;
#include <string>

int main()
{
int *p=new int[5];
//delete p;
delete []p;

p=NULL;

//string *p=new string[5];
//delete p;
//delete []p;
//p=NULL;

return 0;
}

對於int類型和string類型,delete p和delete []p編譯器(vc6.0)會有不一樣的結果,對於int類型delete p和delete []p均可以編譯運行,而 對於string類型,delete p運行

后程序會崩潰。

下面是對這個問題網友的意見與我的總結:

(1)delete 與delete[]都會釋放所有內存,它們的不同點僅在於,根據得到的類型信息是單個指針還是指向數組的指針,來決定調用析構函數的次數。而編譯器對所要刪除的那個指針到底是指向的單一對象還是對象數組的判斷依據就是"[]"的有無。若有'[]'編譯器得到的類型信息就是指向數組的指針,然后調用多次析構函數;若沒有‘[]’編譯器得到的類型信息就是單個指針,只調用一次析構函數。
其實delete操作本身就是做兩件事:
<1> 針對此處內存調用析構函數
<2> 然后釋放該處內存。
(詳見《Effective C++》(2nd)item 5 或 (3rd)item 16)。

 

(2)vc6.0和vs05中,delete和delete[]語句都是調用operator delete(),在vs05中調試,在跟進operator delete()中,可看到有這樣一句“_free_dbg( pUserData, pHead->nBlockUse );”而free要正確工作,有一個必要前提,即傳給它的地址確實是當初申請的內存首地址,否則,會出現assert錯誤。即在重載delete操作符后,某種情況下發現delete操作的指針地址不同於new操作所獲取的地址。從而出現assert錯誤,程序崩潰。

(3)在VC中,對於有顯式析構函數的對象, 在分配數組時其前會有一個4字節前綴用來保存數組元素個數. 如果用delete來釋放數組, 就會導致釋放的內存地址與分配時的內存地址出現4字節偏差, 而導致災難性的錯誤.


(4)那么什么情況下,二者操作的指針地址不匹配呢?
經過反復實驗測試,發現只要對象類型定義有顯式析構函數,那么這個4字節就肯定存在。也就是說,哪怕是我們自定義的一個類類型對象,只要我們沒有為這個類定義析構函數,那么這個4字節問題就不會出現;那么該用delete[]的時候,用delete也不會報錯;那么該用delete的時候,用delete[]也不會報錯,那么...
本論題,由於內置類型沒有析構函數,而string有析構函數,這樣一種巧合,而把問題局限在了內置類型與自定義類型這樣的分類范圍上。所以我們這個問題准確的說,應該是顯式析構函數的存在影響了delete與delete[]的處理。

 

(5)一句話:該用delete[]時莫省略,這是C++標准。

 

原帖如下:

(1)http://topic.csdn.net/u/20080826/16/0c479e3d-737f-45c7-995e-bd316f5fa166.html

(2)http://topic.csdn.net/u/20080221/20/7c7093b9-62d7-4d70-b959-3a06e4327d46.html

(3)http://topic.csdn.net/u/20070712/07/57c7cfc6-7314-400d-86d2-230a72581ea5.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM