C++ 内存管理(c++高质量编程)

一、三种内存分配方式

1、静态存储区:在程序编译时分配,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

2、在栈上创建分配:在执行函数时,函数内的局部变量的存储单元都可以在栈上创建,函数结束时这些单元会自动释放。栈内存分配运算内置于处理器的指令集中,效率高,但是分配的内存容量有限。

3、在堆上分配,也叫动态内存分配。程序在运行时用malloc或new申请任意大小的空间,程序员自己负责在什么时候free或delete释放内存。生命周期由自己决定,灵活,但问题也多。

常见问题:

1、内存分配未成功,却使用了它。

在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=null)进行检查。如果是用malloc或new来申请的,应用if(p==NULL)或if(p!=NULL)进行防错处理。

2、内存分配成功,但未初始化。

出现错误的两种原因:没有初始化;误以为内存的缺省值全为零,导致引用初值错误。

3、内存分配成功并初始化,造成越过内存边界。

例如输出下标多一或少一、for循环次数,导致数组操作越界。

扫描二维码关注公众号,回复: 4439478 查看本文章

4、忘记内存释放造成的内存泄漏。

含有这种错误的函数每调用一次就丢失一块内存。刚开始时系统内存充足,看不到错误,终有一次程序会出现错误提示:内存耗尽。所以动态内存的申请和释放必须配对,程序中malloc与free的使用次数一定要相同,否则会出现错误。new/delete同理。

5、释放了内存却继续使用它。有以下三种情况:

(1)对象调用过于复杂,难以弄清是否释放,所以应该重新设计数据结构,从根本上解决对象管理的混乱局面。

(2)函数的return语句写错,注意不要返回指向“栈内存”的指针或引用,因为该内存体结束时会自动销毁。

(3)使用free或delete后,没有将指针设为NULL,造成野指针。

二、数组和指针

数组要么在静态存储区被创建(如全局数组),要么在栈上。数组名对应着(不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组内容可以改变。

指针可以随时指向任意类型的内存,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。

1、修改内容

a[]表示的是一个字符串变量,它的值可以用下标进行访问修改;*p指向的是一个字符串常量,内容无法修改。

2、复制与比较

不能对数组名直接复制和比较,应用标准库函数strcpy和strcmp比较复制。

3、计算内存容量

用sizeof算出容量(字节数)。注意:char a[]="hello";   sizeof(a)=12字节,但是把数组作为参数传递时,a表示首元素地址,sizeof(a)=4字节.

三、指针参数传递内存

如果函数的参数是一个指针,不要用该指针去申请动态内存。因为编译器要为函数的每个参数制作临时变量,函数体知识修改了临时副本中的内容。如果非要用指针去申请内存,那么应该用“指向指针的指针”,而且函数的参数是&str。

双重指针难以理解,用函数的返回值来传递动态内存。这种方法更加简单:

用函数返回值传递动态内存这种方法虽然好用,但是常常有人把return语句用错。这里强调不要用return返回指向栈内存,因为该内存在函数结束时会自动消亡。

四。内存释放

1、free、delete只是把指针所指的内存释放掉,并没有释放指针本身。通过调试发现指针的地址补位null,只是变成了野指针,要及时的设置成NULL;

2、函数体内的局部变量在函数结束时自动消亡。但是:

void fun()

{

    char *p=(char *)malloc(sizeof(char)*100);//动态内存会自动释放么?

}

(1)指针消亡了,并不代表它所指的内存会被自动释放;

(2)内存被释放了,并不代表指针消亡或成空指针。

五、malloc/free和new/delete

malloc与free是c/c++语言的标准库函数,new/delete是c++运算符。都用于申请动态内存和释放对象。

对于非内部数据类型的对象而言,光用malloc和free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象消亡之前自动调用析构函数。由于malloc/free是库函数,不是运算符,不在编译器控制权之内,不能把构造函数和析构函数的任务强加给malloc/free;

因此c++需要一个能完成动态分配和释放的运算符new/delete。

new/delete 和 malloc/free必须配对使用

六、内存耗尽怎么办

如果在动态申请内存时找不到足够大的空间,malloc和new将返回NULL指针。通常有三种方法解决:

1、判断指针是否NULL,如果是则马上用return终止函数;

2、判断是否为NULL,如果是用exit(1)终止程序;

3、为new/malloc设置异常处理。

七、malloc/free使用要点

malloc函数原型:void * malloc(size_t size);

我们应该把注意力集中在两个要素:“类型转换”“sizeof”。

malloc的返回值为void *类型,所以在调用malloc时要显示的进行类型转换,换成需要的指针类型。

malloc函数本身并不认识要申请的内存是什么类型,他只关心大小(字节数)。所以在32位系统和64位系统下要熟记各种基本类型的字节数。

free函数原型:void free(void * memblock);

八、new/delete使用要点

int *p2=new int[length];使用起来比malloc方便的多,这是因为new内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型而言,new在创建动态对象的同时完成了初始化工作。例如:

Obj *object=new Obj[10];//创建10个动态对象

注意:delete []object;//正确的写法    如果写成delete object   表示delete object[0]是,只delete掉了第一个对象。

猜你喜欢

转载自blog.csdn.net/FF_YTA911/article/details/84679924