new、delete和malloc、free詳解與混用問題

如有錯漏,還望指摘!

以前看到的資料都說,new和delete、new[]和delete[]、malloc和free,必須配套使用,不應該混用。
然而我最近遇到一些相關的問題,因此不得不探究一下,混用了會怎麼樣呢
其實要想知道能不能混用,問題在於:他們有什麼區別
其實很簡單:

  1. malloc只負責分配內存,free只負責釋放內存。
  2. new在分配內存的同時,還會調用構造函數;delete在釋放內存的同時還會調用析構函數。
  3. new[]在分配對應大小內存的同時,還會調用對應次數的構造函數;delete[]同理。

但是這裏其實有一個問題:
delete[]是如何知道到底需要調用多少次析構函數的呢?
原來,new[]在分配時,如果類中顯式定義了析構函數,new會在分配的時候,根據系統的位數額外分配對應的空間(32位系統分配32位空間,也就是4字節,64位系統分配64位空間,也就是8字節)。如對於32位系統,new[2]分配的空間應該如下:
new[]地址分配示意圖
在返回的指針之前,還有一個4字節的header,其中存儲了分配的個數,如這裏就應該是2。

所以我們很容易就能得出結論:

  1. 對於基本類型而言,沒有區別。根據需要new和malloc可以混用,new[]和malloc可以混用,delete、delete[]和free可以混用。
  2. 對於構造函數沒有作用的類,new和malloc可以混用。
  3. 對於構造函數有作用的類,如果想混用,需要顯式調用構造函數的邏輯實現。
  4. 對於沒有顯式定義析構函數的類,delete、delete[]和free可以混用。
  5. 對於顯式定義析構函數的類,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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章