delete p與delete p 的區別

2021-06-28 05:43:27 字數 3181 閱讀 7152

operator new 和 operator delete函式有兩個過載版本,每個版本支援相關的new表示式和delete表示式:

void* operator new (size_t);        // allocate an object

void* operator new (size_t);     // allocate an array

void operator delete (void*);       // free an oject

void operator delete (void*);    // free an array

熟悉c的朋友看到這裡可能會很奇怪:

在c中釋放記憶體用free(void *)【注意這裡只有乙個引數void *】

為什麼到了c++裡會出現兩個!按理說delete 會呼叫free釋放記憶體的啊?

另外delete 是如何知道刪除的物件個數的?

另外一般的教材比如《高質量c++程式設計指南》都會這麼說:

在用delete 釋放物件陣列時,留意不要丟了符號『』。例如

delete objects; // 正確的用法

delete objects; // 錯誤的用法

後者相當於delete objects[0],漏掉了另外99 個物件

這樣的描述當然是錯誤的,而且會誤導觀眾

為了解決問題,開啟vc6,輸入以下**:a;

void

d(a *);

intmain(

intargc,   

char

*argv) 

void

d(a *p)

執行結果:debug assertion failed!

咦,不是說等同於delete p[0]嗎?

為了看看究竟,只好動用那多年以前就忘光了的彙編

經過一番折騰,最後連猜帶蒙得出下面的觀點:

1 如果物件無析構函式(包括不需要合成析構函式,比如注釋掉~a和string s兩行**)

delete會直接呼叫operator delete並直接呼叫free釋放記憶體

這個時候的

new=new (僅在數量上有差異),delete=delete

2 如果物件存在析構函式(包括合成析構函式),則【這個才是重點】:

new 返回的位址會後移4個位元組,並用那4個存放陣列的大小!而new不用後移這四個位元組

delete根據那個4個位元組的值,呼叫指定次數的析構函式 ,同樣delete也不需要那四個位元組

結果就是在不恰當的使用delete 和delete 呼叫free的時候會造成4個位元組的錯位,最終導致debug assertion failed!

再回到《高質量c++程式設計指南》:

delete objects; // 正確的用法

delete objects;  // 錯誤的用法

後者相當於delete objects[0],漏掉了另外99 個物件

嚴格應該這樣說:後者相當於僅呼叫了objects[0]的析構函式,漏掉了呼叫另外99 個物件的析構函式,並且在呼叫之後釋放記憶體時導致異常(如果存在析構函式的話),如果物件無析構函式該語句與delete objects相同

注:1 測試環境vc6

2 不保證觀點正確

3 歡迎指正

由new分配的乙個陣列空間,比如說 int *array=new int[50],當用delete釋放這個空間時,用語句delete array和delete array是否等價!

c++告訴我們在**用 new 分配的單個物件的記憶體空間的時候用 delete,**用 new 分配的一組物件的記憶體空間的時候用 delete。 

關於 new 和 delete,其中又分為兩種情況:(1) 為基本資料型別分配和**空間;(2) 為自定義型別分配和**空間。 

對於 (1),上面提供的程式a可以證明了 delete 和 delete 是等同的。 

程式a: 

#include

#define buff_size 10240 

int main(int argc, char *argv) 

return 0; 

} 但是對於 (2),情況就發生了變化。請看下面的程式。 

#include

#define buff_size 10240 

class ttt 

; ~ttt() 

; private: 

int a; 

char* aa; 

int inta[1024]; 

}; int main(int argc, char *argv) 

return 0; 

} 大家可以自己執行這個程式,看一看 delete p1 和 delete p1 的不同結果,我就不在這裡貼執行結果了。 

從執行結果中我們可以看出,delete p 在**空間的過程中,只有 p[0] 這個物件呼叫了析構函式,其它物件如 p[1]、p[2] 等都沒有呼叫自身的析構函式,在析構函式中的記憶體釋放操作將不會被執行(引發記憶體洩漏),已使用記憶體不斷增加,這就是問題的癥結所在。如果用 delete,則在**空間之前所有物件都會首先呼叫自己的析構函式,已使用記憶體不會不斷增加。 

基本型別的物件沒有析構函式,所以**基本型別組成的陣列空間用 delete 和 delete 都是應該可以的;但是對於類物件陣列,只能用 delete。對於 new 的單個物件,只能用 delete 不能用 delete **空間。

#include ; 

#include "xercesc/dom/dom.hpp" 

int main()

~t() 

};int main()

大家可以自己執行這個程式,看一看 delete p1 和 delete p1 的不同結果,我就不在這裡貼執行結果了。 

從執行結果中我們可以看出,delete p1 在**空間的過程中,只有 p1[0] 這個物件呼叫了析構函式,其它物件如 p1[1]、p1[2] 等都沒有呼叫自身的析構函式,這就是問題的癥結所在。如果用 delete,則在**空間之前所有物件都會首先呼叫自己的析構函式。 

基本型別的物件沒有析構函式,所以**基本型別組成的陣列空間用 delete 和 delete 都是應該可以的;但是對於類物件陣列,只能用 delete。對於 new 的單個物件,只能用 delete 不能用 delete **空間。 

所以乙個簡單的使用原則就是:new 和 delete、new 和 delete 對應使用。

delete p和delete p的區別

原文 operator new 和 operator delete函式有兩個過載版本,每個版本支援相關的new表示式和delete表示式 void operator new size t allocate an object void operator new size t allocate an ...

SQL與NoSQL MySQL與NoSQL的融合

寫這一篇內容的原因是mysql5.6.2突然推出了memcached的功能。nosql to innodb with memcached的出現,可以看出nosql對關聯式資料庫的確產生了巨大的影響,個人覺得這是乙個非常大的進步,可以讓開發人員更加方便的使用nosql和關聯式資料庫。nosql一般被認...

指標與陣列 a與 a區別

假設宣告了乙個陣列a,則 a表示陣列a的首位址,a與 a 0 表示陣列a首元素的首位址,那麼 a 1與a 1有哪些區別呢?通過下面的實驗來說明。int i 0 int a 5 int p int a 1 for i 0 i 5 i printf a 0x p,a 0x p,a 1 0x p n a,...