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,...