一、简单谈一下内存分配的几种方式
1.从静态存储区域分配
内存在程序编译的时候以近乎分配好,这块内存在程序的整个运行期间都存在。(例如全局变量、static变量)
2.在栈上创建
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。占内存分配运算内置于存储器的指令集中,效率很高,但是分配的内存容量有限。
3.从堆上分配(动态内存分配)
程序在运行的时候用malloc或new申请任意多少的内存,然后再自行选择再何时free和delete释放内存。动态内存的生存期由我们自己决定。
malloc与free是C++/C语言的标准库函数。
new与delete是C++运算符。
二者都可以用于申请动态内存和释放内存。
二、那么有了malloc/free为什么还要new/delete?
因为对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象再创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc和free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行狗杂偏函数和析构函数的任务强加于malloc和free。
所以C++语言需要一个能完成动态分配内存和初始化工作的运算符new,以及一个能完成清理和释放内存工作的运算符delete。
三、malloc/free和new/delete的使用
函数malloc的原型:
void* malloc(size_t size);
用malloc申请一块长度为length的整数类型的内存:
int p = (int)malloc(sizeof(int) * length);
1.malloc返回值类型是void*,所以在调用malloc时要显示地进行类型转换,将void*转换成所需要的指针类型。
2.malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数
void A
{
Obj *a = (Obj*)malloc(sizeof(obj)); //申请动态内存
a->Init(); //初始化
//...
a->Destroy(); //清除工作
free(a); //释放内存
}
malloc和new对比使用
malloc的使用
int p1 = (int)malloc(sizeof(int) * length);
new的使用
int *p2 = new int[length];
为什么new比malloc简单那么多?
因为new内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型的对象而言,new再创建动态对象的同时完成了初始化工作。
//对于对象有多个构造函数,new的语句也有多种形式
class Obj
{
public:
Obj(void); //无参数的构造函数
Obj(int x); //带一个参数的构造函数
...
}
void Test(void)
{
Obj *a = new Obj;
Obj *b = new Obj(1); //初值为1
...
delete a;
delete b;
}
使用malloc/free和new/delete注意事项
- 用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。如果指针p是函数的参数,那么再函数的入口处用assert(p!=NULL)进行检查。如果malloc或new来申请内存,应该用if(p==NULL)或if(p!=NULL)进行防错处理。
- 数组和动态内存要赋初值。防止将未被初始化的内存作为右值使用。
- 避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
- 动态内存的申请与释放必须配对,防止内存泄漏。
- 用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
什么是“野指针”?产生野指针的原因有哪些?
“野指针”不是NULL指针,是指向“垃圾”内存的指针。“野指针”非常危险的,if语句对它不起作用。
产生“野指针”的原因:
(1)指针变量没有初始化。(任何指针再被创建的时候不会自动成为NULL指针,它的缺省值是随机的。)
(2)指针p被free或者delete之后没有置为NULL。
(3)指针操作超越变量的作用范围。
四、动态内存会被自动释放吗?
函数体内的局部变量再函数结束时自动消亡。
同时我们应该注意
(1)指针消亡了,不代表它所指的内存会被自动释放。‘
(2)内存被释放了,不代表指针会消亡或者成为NULL指针。
五、new/delete和malloc/free的区别
- 它们都是动态管理内存的入口。
- malloc/free是C/C++标准库的函数,new/delete是C++操作符。
- malloc/free需要手动计算类型大小且返回值为void*,new/delete可自己计算类型的大小对应类型的指针。
- malloc/free只是动态分配内训空间/释放空间。而new/delete除了分配空间还会调用构造析构函数进行初始化与清理。
- new/delete的底层调用了malloc/free.
- malloc/free申请空间后判空,new/delete则不需要。
- new直接跟类型,malloc跟字节数个数。
- new 开辟内存失败是抛出 bad_alloc 类型的异常,因此代码上要捕获该类型的异常才能正确的判断堆内存是否分配成功;malloc 内存开辟失败返回的是 NULL 指针
- new 和 delete 不仅仅是运算符,它们实际上是运算符重载函数的调用,对应的函数名是 operator new 和 operator delete,可以在全局或者类的作用域中提供自定义的 new 和delete 运算符的重载函数,以改变默认的 malloc 和 free 内存开辟释放行为
- malloc 开辟的内存永远是通过 free 来释放的;而 new 单个元素内存,用的是 delete,如果 new[]数组,用的是 delete[]来释放内存的。
int *p1 = (int*)malloc(sizeof(int)); //根据传入字节数开辟内存,没有初始化
int *p2 = new int(0);//根据指定类型int开辟一个整型内存,初始化为0
int *p3 = (int*)malloc(sizeof(sizeof(int)*100);//开辟400个字节的内存,相当于包含100个整形元素的数组,没有初始化
int *p4 = new int[100]();//开辟400个字节的内存,100个元素的整形数组,元素都初始化为0