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;
}
原创文章 34 获赞 41 访问量 5962

猜你喜欢

转载自blog.csdn.net/qq_44844115/article/details/99433233