/ new-->申請空間+調用構造函數?先申請空間再調用構造函數// delete-->釋放空間+調用析構函數?先調用析構函數再去釋放空間// 有沒有問題?--什么問題?void FunTest1(){Test* p1 = (Test*)malloc(sizeof(Test));Test* p2 = new Test;// free(p1);// delete p2;delete p1;free(p2);}
非內部數據類型:編譯器自身不認識需要用戶自己定義的而講
對于非內部數據類型光用malloc和free是無法滿足動態對象的,因為對象在創建的時候需要編譯器自動調用構造函數,而malloc是一個庫函數不是運算符,不在編譯器的控制范圍之內自然不能把調用構造函數的任務強加給malloc,而new可以看成是兩步:1>動態分配內存相當于malloc
2>調用類的構造函數
new建立的是一個對象
malloc是分配的一塊內存。
free和delete也是同理:free只是單純的釋放分配的內存,并不能調用析構函數完成清理工作。
// 析構函數如果顯式給出程序崩潰, 為什么?void FunTest2(){Test* p1 = new Test;Test* p2 = new Test[10];delete[] p1;delete p2;}
Test* p1 = new Test;創建了單個對象只調用了一次構造函數
Test* p2 = new Test[10];創建了10個類對象調用了次構造函數
如果我們顯示定義了析構函數,new Test[1]他仍然會比實際用戶需要的字節數多出4個字節,因此在釋放的時候他會先將cout取出來,然后再去調用count次析構函數。最后再釋放內存。
delete[] p1;它本來是要釋放之前創建單個對象的內存的,并且之前只調用了一次構造函數也應該只析構一次,但是此時卻多次調用了析構函數將本來不屬于這個對象的空間當成了該類型的對象進行清理程序自然會崩潰,而如果我們將析構函數不顯示給出,那么他相當于沒有調用析構函數自然不會去清理不屬于該對象的空間程序也不會崩潰。如果去我們顯式的給出析構函數,那我們知道它會先去取出前4個字節中保存的cout也就是創建對象的個數,然后去析構count次那么你就會把不屬于你的空間也清理了,因此程序會崩潰。如果我們不顯式的給出析構函數那么它就不會多出那4個字節
delete p2;
它本來是要將之前創建的10個對象的內存釋放掉的,之前調用了10次構造函數,那么此時它也應該調用10次析構函數去完成清理工作而此時的delete相當于只清理了第一個對象,并沒有完成清理完所有對象自然會出問題。
---------------------------------------------------------------------上述都是對類對象即非內置類型來講的。
而對于內置類型的沒有構造和析構函數,因此在釋放內存的時候delete和delete[]的效果是一樣的,不存在匹配問題。
無論new還是new[],C++必須知道返回指針所指向的內存塊的大小,否則它就不可能正確地釋放掉這塊內存,但是在用new[]為一個數組申請內存時,編譯器還會悄悄地在內存中保存一個整數,用來表示數組中元素的個數(這是編譯器懂得手腳)。因為在delete一塊內存時,我們不僅要知道指針指向多大的內存,更重要的是要知道指針指向的數組中對象的個數。因為只有知道了對象數量才能一一調用它們的析構函數,完成對數組中所有對象的清理。如果使用的是delete,則編譯器只會將指針所指的對象當作單個對象來處理。所以對于數組,需要使用delete[]來處理;符號[]會告訴編譯器在delete這塊內存時,先去獲取保存的那個元素數量值,然后再進行一一清理
對于new和delete的深層認識:
new:
我們都知道new[cout]在申請分配的內存時候底層是調用了Operator new[]函數---[]里面代表所要申請的字節數如果我們顯式定義了析構函數那么他申請的字節數要多加4個字節,
然后調用了operator new函數(參數也是字節數同剛才一樣
然后調用了malloc函數去為我們真正的申請內存空間
如果顯式定義了析構函數那么我們將cout放入用戶數據起始地址的位置也就是將cout放入前4個字節中。
接著我們調用cout次構造函數。
由此我們可以知道析構函數顯式給出new出來的字節數會多出來4個去存放cout。
delete:
在使用delete這個操作符的時候如果之前我們顯式定義了析構函數那么我們首先將cout取出來然后調用cout次的析構函數,然會在調用operator delete[]函數--接著調用operator delete函數---然后在調用free函數去釋放。
當然我們的operator new函數可以自己寫成類的成員函數
也可以寫成普通函數
也可以直接調用系統自己寫函數
當然這三個函數會有先后順序,如果三個同時給出則會先調用我們寫成的類成員函數,然后調用普通函數最后才是系統自己的函數,當然在使用new時如果調用自己寫的
operator new函數之后也會去調用構造函數,在開辟完空間之后就會去自動調用構造函數去創建對象。
定位new表達式不用開辟空間只調用它的構造函數
我們可以用定位new來模擬實現new
class Test { public : Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } Test *New(size_t size) { Test*p = (Test*)malloc(size); if (p == NULL) { return NULL; } new(p)Test; return p; } PRivate:int _Data; }; int main() { Test p; Test *pt=p.New(44); system("pause"); return 0; }
當然上面是直接創建單個對象
我們也可以用定位new來實現new[]
class Test{public: Test() { cout << "Test()" << endl; } ~Test() { cout << "~Test()" << endl; } Test *New(size_t count)//new出count個對象 { int *p = (int *)malloc(count*sizeof(Test)+4); if (p == NULL) { return NULL; } *p = count; Test *pt = (Test *)(p + 1); for (int idx = 0; idx < count; idx++) { new (pt + idx)Test(); } return pt; }private:int _Data;};int main(){ Test p; cout << "please look" << endl; Test *pt = p.New(4); system("pause"); return 0;}
我們可以看到用New()創建了4個對象調用了4次構造函數。
新聞熱點
疑難解答