如有错漏,还望指摘!
以前看到的资料都说,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;
}