C++进阶学习——内存管理

本文详细探讨了C++的内存管理,包括内存分配方式、栈与堆的区别、内存使用注意事项、指针与数组对比、内存泄露及其检测工具。特别讨论了SmartPoints在资源管理中的应用,以及如何通过栈对象降低资源泄露风险。此外,分析了malloc/free与new/delete的差异,并阐述了C++内存回收机制。
摘要由CSDN通过智能技术生成

一篇大佬写的超级详细的C++内存管理的教学,链接: https://blog.csdn.net/caogenwangbaoqiang/article/details/79788368
整理笔记备忘。

1 内存管理

1.1 内存分配方式

 栈、堆、自由存储区、静态/全局存储区、常量存储区

  1. 栈:由编译器维护,用于存放局部变量
  2. 堆:由程序员自行维护,对应的操作是new()和delete()
  3. 自由存储区:存放由malloc()/free()管理的内存
  4. 静态/全局存储区:静态变量static和全局变量存放的位置
  5. 常量存储区:只存放常量的内存空间

1.2 栈和堆的区别

空间小(1M左右) 空间大(4G)
由编译器维护 由程序员自行维护
有专用的寄存器和指令,分配效率高 由C/C++函数库实现,有复杂的空间分配算法,分配效率低
不易产生内存碎片(栈结构) 频繁地new和delete会导致大量的内存碎片,程序执行效率会下降
内存地址由高地址向低地址生长(先进后出) 内存由低地址向高地址生长
静态/动态分配(alloc) 动态分配

1.3 使用内存时要注意

  1. 对于分配的内存,要校验是否分配成功
  2. 对分配成功的内存要赋初值
  3. 使用时要防止越界,做边界检查
  4. 动态内存操作必须配对,new/delete,malloc/free
  5. 释放了的内存不能继续使用
    (1) 指针指向的内存释放之后,指针没有置为NULL,会变成野指针
    (2) 在return返回值时避免返回局部变量的指针或引用,因为局部变量在该函数执行完成之后就会被释放

1.4 指针和数组的对比

  1. 内容修改的区别
     数组“对应”着一段内存空间,其内容可以通过对数组的操作进行自由修改
     指针“指向”一段内存空间,指针本质是变量,保存着所指向的数据的地址,指针指向的数据能否修改,取决于这个数据的类型,如果是常量则不可修改,这种错误编译器检查不出来,但实际运行时会出错
  2. 内容复制和比较
     数组复制不能用a=b,需要用strcpy()函数,数组的比较也要使用strcmp()函数
     指针复制可以用p=q,但不是将数据复制,而是将q指向的数据存放的地址拷贝给p,如果修改这个数据,则*p,*q的值都会发生变化,如果想将数据进行拷贝,可以用malloc函数为p申请一块大小为sizeof(T)(strlen(*q)+1)的内存,再通过strcpy函数拷贝,比较大小也是要用到strcmp函数
     sizeof(数组),得到的是数组内数据的长度(字节)
     sizeof(指针),得到的是该指针的类型的长度
    注意,当数组作为函数的参数传递时,会自动退化为同类型的指针,此时sizeof函数无法得到这个数组的大小

1.5 指针参数传递内存

  如果指针作为一个函数的参数,在这个函数内为指针申请内存是不会改变源指针的,因为编译器会为函数的参数创建副本_p,申请内存只会使_p得到一段内存(实际上这块内存在使用之后并没有销毁,也就是产生了内存泄露)
  如果想要在函数里为指针申请内存,就需要传入指向指针的指针&p,或者使用函数返回值来传递p,但参见上文,不能将指向栈空间的指针作为返回值传递,需要使用new或malloc申请内存

1.6 野指针

  野指针是指向“无用的”数据的指针,野指针产生的情况可能有:

  1. 指针没有初始化,创建指针变量的时候一定要赋值
  2. 在delete或free释放指针指向的内存空间后,没有将指针置为NULL
  3. 指针指向的内容生命周期结束,而指针本身还在使用,此时的指针也会变成野指针

1.7 malloc/free和new/delete的区别

  1. malloc/free是标准库函数,new/delete是运算符
  2. C程序只能用malloc/free管理动态内存
  3. 非内部数据类型的对象,new/delete执行时会调用其构造函数和析构函数,而内部数据类型不存在构造和析构函数。
  4. 其实new和delete的底层还是malloc和free

1.8 内存耗尽

 当new/malloc函数返回一个空指针时表示无法申请一段指定大小的内存,此时需要使用return终止该函数或exit(1)终止整个程序
 32位以上的系统基本不存在内存耗尽的情况(因为虚拟内存技术,当内存不够用时,调用硬盘空间作为虚拟内存),但还是要在申请内存时检查申请是否成功

1.9 new/delete使用注意事项

 使用new时会自动调用类的构造函数进行初始化,当构造函数不唯一时,new也支持通过参数类型和数量执行所需的构造函数,如

Obj *obj=new Obj;
Obj *obj=new Obj(参数列表);

注意在new一个Obj[]类型的对象时无法指定参数,只能调用默认的无参数构造函数,在之后要释放该对象时,要同样调用delete[]而不是delete

Obj *obj=new Obj[length];
delete []obj
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值