目錄
- 一、對new [] delete [] 的理解
- 1、delete的[]遺漏會帶來什么影響
- 二、以示例探討
- 三、cookie的理解
一、對new [] delete [] 的理解
new的對象是個array類型的。
Complex* pca = new Complex[3];
//喚起三次ctor
//無法借由參數給予初值
...
delete[] pca; //喚起3次dtor
如下圖,new出來的是一個array,大小為3.
new的時候要調用3次ctor,delete的時候需要調用3次dtor。分配一個array的時候,會順帶分配一個cookie,用來記錄信息,最主要的就是array的長度了。
1、delete的[]遺漏會帶來什么影響
如果delete后面不加[],編譯器會以為只需要delete所指的對象,所以只會調用一次dtor,然而cookie記錄中的array長度并沒有改變,此時就會少還一些內存給操作系統,從而導致內存泄漏。
str1、str2、str3會被完整回收,但是在回收之前需要調用析構函數。由于string在構造上會帶有一個指針,指針指向真正的字符串的內存空間。調用三次dtor,會被很干凈地清掉。而少加了[],會就只調用一次dtor,導致三塊只釋放掉了一塊。
注意泄露的內存不是str1 2 3,而是指向的真正的字符串的內存空間。
**如果這里的array里面的元素類型是復數Complex,就不會造成內存泄漏,因為復數里面不包含指針。所以調用三次和調用一次也就無所謂了。**不過為了統一,還是要加上[]。
二、以示例探討
示例代碼:
A有一個默認構造函數,因為我們在new一個數組的時候不能一一地給定值,我們new是時候會調用三次構造函數。
構造函數和析構函數會在屏幕上輸出占用內存位置
class A
{
public:int id;A() : id(0) { cout << "default ctor. this=" << this << " id=" << id << endl; }A(int i) : id(i) { cout << "ctor. this=" << this << " id=" << id << endl; }~A() { cout << "dtor. this=" << this << " id=" << id << endl; }
};A* buf = new A[size]; //default ctor 3 次. [0]先於[1]先於[2])//A必須有 default ctor, 否則 [Error] no matching function for call to 'jj02::A::A()'A* tmp = buf; cout << "buf=" << buf << " tmp=" << tmp << endl; for(int i = 0; i < size; ++i)new (tmp++) A(i); //3次 ctor cout << "buf=" << buf << " tmp=" << tmp << endl;delete [] buf; //dtor three times (次序逆反, [2]先於[1]先於[0])
執行結果:
1、默認構造函數,默認id= 0 ;
2、this指針會自動移動,間距是一個對象的大小(int 4個字節)
3、移動指針,設初值,調用有參構造函數
4、需要注意這樣的語法new(指針,指向已經分配的內存,我們在指針所指的地方進行設置初值) A(i)
,這屬于placement new 的用法,之后的筆記會詳細講到。
5、循環過后id被修改,地址沒有被修改
6、最后delete[],觀察可知,調用了3次析構函數,析構的次序與構造的次序相反。(不同的編譯環境析構次序可能不同)
三、cookie的理解
在做內存管理的時候,會有一個很大的訴求,就是不要這個cookie,所以cookie的存在以及大小是我們需要理解度的。
下面是VC6中,觀察malloc給我們的內存布局:而我們獲得的值指向分配的10個int數據的起始地址*pi.可以看到,除了我們認定的需要的10個int外,malloc還會分配32bytes和4bytes(橙色部分)。另外還有上cookie和下cookie,負責記錄整塊的大小。
另外還有一個pad區域,這是由于在VC6下,malloc分配的內存必須是16bytes的倍數,如果不是,則需要填充額外內存使之為16bytes的倍數。
注意cookie記錄的分配的內存大小為60h,不過最后一個bit要被用做on or off 的狀態的切換,所以為61h。(存疑,不是很理解這句話,之后再補上理解。)上下cookie的數值一樣。
這里的delete加不加[]是沒有影響的。
如果這里我們不是存放的int類型的數據,而是放的是一個對象,并且它的析構函數是有意義的,此時編譯器創造array的方式會有所不同。
注意每個demo對象中存放的是三個int,我們new了3個demo,分配的內存與之前相比多了一個3,即3個demo。
delete不加[],編譯器將p當做普通指針,指向一塊對象,然后以一塊對象的方式去解釋布局,但是此刻的布局與之前不同,多了一個3,所以解釋會發生錯誤。
使用array new和array delete時,內存塊分配是不一樣的。array元素個數被寫到內存塊里去了。
60h內存計算方式:
60h = 32(debugger header) + 4(3:元素個數,int類型,4個bytes) + 3 x 12 (3個 demo object) + 4 (no man land) +12(pad) + 4 x 2(上喜下兩個cookie)= 96個byte = 60h個byte(pad是會變動的)