如有錯漏,還望指摘!
以前看到的資料都說,new和delete、new[]和delete[]、malloc和free,必須配套使用,不應該混用。
然而我最近遇到一些相關的問題,因此不得不探究一下,混用了會怎麼樣呢?
其實要想知道能不能混用,問題在於:他們有什麼區別?
其實很簡單:
- malloc只負責分配內存,free只負責釋放內存。
- new在分配內存的同時,還會調用構造函數;delete在釋放內存的同時還會調用析構函數。
- new[]在分配對應大小內存的同時,還會調用對應次數的構造函數;delete[]同理。
但是這裏其實有一個問題:
delete[]是如何知道到底需要調用多少次析構函數的呢?
原來,new[]在分配時,如果類中顯式定義了析構函數,new會在分配的時候,根據系統的位數額外分配對應的空間(32位系統分配32位空間,也就是4字節,64位系統分配64位空間,也就是8字節)。如對於32位系統,new[2]分配的空間應該如下:
在返回的指針之前,還有一個4字節的header,其中存儲了分配的個數,如這裏就應該是2。
所以我們很容易就能得出結論:
- 對於基本類型而言,沒有區別。根據需要new和malloc可以混用,new[]和malloc可以混用,delete、delete[]和free可以混用。
- 對於構造函數沒有作用的類,new和malloc可以混用。
- 對於構造函數有作用的類,如果想混用,需要顯式調用構造函數的邏輯實現。
- 對於沒有顯式定義析構函數的類,delete、delete[]和free可以混用。
- 對於顯式定義析構函數的類,delete[]和new[]必須配套使用,delete和free如果想混用,free需要顯式調用析構函數。
代碼:
//構造函數和析構函數都沒有作用。可以隨意混用。
class test1{
public:
test1(){}
}
int main(void){
/*
這裏用任意方式分配的內存都可以用任意方式釋放
*/
//test1 *ptr = new test1;
test1 *ptr = new test1[3];
//test1 *ptr = (test1*)malloc(sizeof(test1));
//delete ptr;
//delete[] ptr;
free(ptr);
}
//構造函數有作用。
//沒有顯示定義析構函數,因此delete、delete[]、free可以混用
class test2{
public:
test2(){
init();
}
inline void init(){
cout << "constructor" << endl;
}
}
int main(void){
//test2 *ptr = new test2;
//test2 *ptr = new test2[3];
/*
這裏如果想用malloc,必須顯示調用構造函數的邏輯。
注:由於構造函數無法被顯式調用,因此必須另寫一個其實現邏輯,也就是這裏的init()函數。
*/
test2 *ptr = (test2*)malloc(sizeof(test2));
ptr->init();
//delete ptr;
delete[] ptr;
//free(ptr);
}
//構造函數沒有有作用。new、new[]、malloc可以混用
//顯示定義析構函數
class test3{
public:
test3(){}
~test3(){
cout << "destructor" << endl;
}
}
int main(void){
//test3 *ptr = new test3;
test3 *ptr = (test3*)malloc(sizeof(test3));
//delete ptr;
/*
必須顯示調用析構函數
*/
ptr->~test3();
free(ptr);
/*
只要定義了析構函數,即使析構函數內是空的,delete[]和new[]也必須配套使用,否則會一直調用析構函數
*/
//test3 *ptr = new test3[3];
//delete[] ptr;
}
//對於32位系統,new[]和delete[]的非配套使用。
//顯示定義析構函數
class test3{
public:
test3(){}
~test3(){
cout << "destructor" << endl;
}
}
int main(void){
int n = 3;
/*
new[]和free混用
*/
test3 *ptr1 = new test3[n];
//模擬delete[]
for(int i = 0; i < n; i++){
(ptr1 + i)->~test3();
}
ptr = (test3*)( ((char*)ptr) - 4 );
free(ptr);
/*
malloc和delete[]
*/
//模擬new[]
test3* ptr2 = (test3*)malloc(4 + n * sizeof(test3)); //如果是64位系統,這裏4換成8
int32_t* temp = (int32_t*)ptr2; //如果是64位系統,這裏是int64_t
*temp = n;
temp++;
ptr2 = (test3*)temp;
for(int i = 0; i < n; i++){
(ptr2 + i)->init();
}
delete[] ptr2;
}