C++(malloc/free和new/delete)
C++(malloc/free和new/delete)
用于测试的类A
/**
* @brief 用于检测new和delete对构造函数和析构函数
*
*/
class A{
public:
A(){
std::cout<<"call constructor:A()"<<std::endl;
}
~A(){
std::cout<<"call destructor:A()"<<std::endl;
}
};
new和delete的使用
1、new和delete关于构造函数和析构函数的调用
/**
* @brief 用于探索delete数组时的情况.用delete[]和delete
* 函数输出:
delete[]
call constructor:A()
call constructor:A()
call destructor:A()
call destructor:A()
delete
call constructor:A()
call constructor:A()
call destructor:A()
munmap_chunk(): invalid pointer
Aborted (core dumped)
*/
void test1(){
std::cout<<"delete[]"<<std::endl;
A *twoA = new A[2];
delete[] twoA;
std::cout<<"delete"<<std::endl;
twoA = new A[2];
delete twoA;
std::cout<<std::endl;
}
可见,new一个对象就会调用一次构造函数,delete一个对象就会调用一次析构函数。但是要delete数组时,必须使用,否则会出现报错:munmap_chunk(): invalid pointer
Aborted (core dumped)
2、模仿new失败的情况:申请一个很大的数组
/**
* @brief 探索new失败的情况
抛出异常:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
*/
void test4(){
//申请失败抛异常
int* ptr1 = new int[(long long)9999999999999999];
}
抛出异常:std::bad_alloc
3、对同一个对象delete两次
/**
* @brief 对同一个对象delete两次
* 函数输出:
call constructor:A()
call destructor:A()
call destructor:A()
free(): double free detected in tcache 2
Aborted (core dumped)
*/
void test5(){
A *a = new A();
delete a;
delete a;
}
可见,delete两次后会出现无法解决的报错:free(): double free detected in tcache 2。注意:虽然delete两次不合法,但是根据输出可知析构函数还是调用了两次。
4、尝试使用delete后的空间
/**
* @brief 尝试使用delete后的空间
* 函数输出
call constructor:A()
call destructor:A()
call constructor:A()
before deelte int->i : 100
after deelte int->i : 1498309783
call destructor:A()
*/
void test6(){
A *a = new A();
int *i = new int(100);
delete a;
// delete后,尝试访问a
A a_copy = *a;
a = new A();
printf("before deelte int->i : %d\n", *i);
delete i;
printf("after deelte int->i : %d\n", *i);
}
可见,delete之后的对象还是可以继续访问(不报错),但是内容是未知的。
malloc和free的使用
1、malloc和free关于构造函数和析构函数的调用
/**
* @brief 用于探索free数组时的情况.用delete[]和delete
* 函数无输出:证明malloc没有调用构造函数、free没有调用析构函数
*/
void test2(){
A *twoA = (A*)malloc(sizeof(A)*2);
free(twoA);
}
可见,malloc没有调用构造函数、free没有调用析构函数。
2、模仿malloc失败的情况:申请一个很大的数组
/**
* @brief malloc失败的情况
* 函数输出:ptr1 is NULL
*/
void test8(){
//申请失败抛异常
int* ptr1 = (int*)malloc(sizeof(int) * (long long)9999999999999999);
if (ptr1 == NULL){
printf("ptr1 is NULL\n");
}
}
可见,malloc失败并不会像new失败一样抛出异常。只是返回NULL。
3、尝试使用free后的空间
/**
* @brief 用于探索free后的空间是否可以继续使用
* 函数输出
before free :
nums[0] = 0
nums[1] = 1
after free :
nums[0] = 1575797714
nums[1] = 5
after free and assign :
nums[0] = 2
nums[1] = 2
*/
void test3(){
int *nums = (int*)malloc(sizeof(int)*2);
nums[0] = 0; nums[1] = 1;
printf("before free :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
free(nums);
printf("after free :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
nums[0] = nums[1] = 2;
printf("after free and assign :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
}
可见,free后的数组依然可以访问和赋值。只是访问free后的数组内容是未知的。
4、对同一个对象free两次
/**
* @brief 对同一个对象free两次
* 函数输出:
free(): double free detected in tcache 2
Aborted (core dumped)
*
*/
void test7(){
int *i = new int(100);
printf("before free, i = %d\n", *i);
free(i);
printf("after first free, i = %d\n", *i);
free(i);
printf("after second free, i = %d\n", *i);
}
可见,对于同一个对象free两次,会报错:
free(): double free detected in tcache 2
Aborted (core dumped)且printf语句没有打印。
总结
new和delete
- new和delete是运算符,不需要包含任何头文件即可使用
- new的工作有两步:
- 申请空间
- 对空间进行初始化(调用类的构造函数)
- delete的工作有两步:
- 对空间进行资源清理(调用类的析构函数)
- 释放空间
- new失败时会抛出异常
malloc和free
- malloc和free是函数
- malloc需要传入空间的大小,并且返回的是void*,需要手动强制类型转换
- malloc和free都只是简单的申请和释放空间
两者的联系
相同点
- new和malloc都是从堆申请空间
- delete和free都是释放空间,并且都是将内存标记为可用内存,释放后可以继续访问
- 对同一对象重复free、delete都是会报错的
不同点
- new和delete会调用构造(析构)函数,而malloc和free不会
- malloc需要指定计算空间大小和强制类型转换,而new不需要
- malloc失败是返回NULL,而new失败是抛出异常
使用技巧
在c++中尽量使用new和delete,避免使用malloc和free。
本文的全部代码
/**
* @file test1.cpp
* @author your name (you@domain.com)
* @brief
* @version 0.1
* @date 2022-08-15
*
* @copyright Copyright (c) 2022
*
*/
#include<iostream>
/**
* @brief 用于检测new和delete对构造函数和析构函数
*
*/
class A{
public:
A(){
std::cout<<"call constructor:A()"<<std::endl;
}
~A(){
std::cout<<"call destructor:A()"<<std::endl;
}
};
/**
* @brief 用于探索delete数组时的情况.用delete[]和delete
* 函数输出:
delete[]
call constructor:A()
call constructor:A()
call destructor:A()
call destructor:A()
delete
call constructor:A()
call constructor:A()
call destructor:A()
munmap_chunk(): invalid pointer
Aborted (core dumped)
*/
void test1(){
std::cout<<"delete[]"<<std::endl;
A *twoA = new A[2];
delete[] twoA;
std::cout<<"delete"<<std::endl;
twoA = new A[2];
delete twoA;
std::cout<<std::endl;
}
/**
* @brief 用于探索free数组时的情况.用delete[]和delete
* 函数无输出:证明malloc没有调用构造函数、free没有调用析构函数
*/
void test2(){
A *twoA = (A*)malloc(sizeof(A)*2);
free(twoA);
}
/**
* @brief 用于探索free后的空间是否可以继续使用
* 函数输出
before free :
nums[0] = 0
nums[1] = 1
after free :
nums[0] = 1575797714
nums[1] = 5
after free and assign :
nums[0] = 2
nums[1] = 2
*/
void test3(){
int *nums = (int*)malloc(sizeof(int)*2);
nums[0] = 0; nums[1] = 1;
printf("before free :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
free(nums);
printf("after free :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
nums[0] = nums[1] = 2;
printf("after free and assign :\n nums[0] = %d\n nums[1] = %d\n", nums[0], nums[1]);
}
/**
* @brief 探索new失败的情况
抛出异常:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
*/
void test4(){
//申请失败抛异常
int* ptr1 = new int[(long long)9999999999999999];
}
/**
* @brief 对同一个对象delete两次
* 函数输出:
call constructor:A()
call destructor:A()
call destructor:A()
free(): double free detected in tcache 2
Aborted (core dumped)
*/
void test5(){
A *a = new A();
delete a;
delete a;
}
/**
* @brief 尝试使用delete后的空间
* 函数输出
call constructor:A()
call destructor:A()
call constructor:A()
before deelte int->i : 100
after deelte int->i : 1498309783
call destructor:A()
*/
void test6(){
A *a = new A();
int *i = new int(100);
delete a;
// delete后,尝试访问a
A a_copy = *a;
a = new A();
printf("before deelte int->i : %d\n", *i);
delete i;
printf("after deelte int->i : %d\n", *i);
}
/**
* @brief 对同一个对象free两次
* 函数输出:
free(): double free detected in tcache 2
Aborted (core dumped)
*
*/
void test7(){
int *i = new int(100);
printf("before free, i = %d\n", *i);
free(i);
printf("after first free, i = %d\n", *i);
free(i);
printf("after second free, i = %d\n", *i);
}
/**
* @brief malloc失败的情况
* 函数输出:ptr1 is NULL
*/
void test8(){
//申请失败抛异常
int* ptr1 = (int*)malloc(sizeof(int) * (long long)9999999999999999);
if (ptr1 == NULL){
printf("ptr1 is NULL\n");
}
}
int main(){
// test1();
// test2();
// test3();
// test4();
// test5();
// test6();
// test7();
test8();
return 0;
}

浙公网安备 33010602011771号