C++入门5--C++内存管理
1.C/C++的内存分布
【说明】
1.栈:主要用于存储非静态的局部变量/函数参数/返回值等,栈是向下生长的。
2.堆:堆主要是程序运行时的动态内存分配,堆是向上生长的,堆是向上生长的,但是地址也不一定越来越大,因为如果前面的内存被释放了,就可能被拿来继续使用,这样的话就会变小
3.数据段:全局变量或者静态数据
4.代码段:可执行的代码/只读常量
例题:
1 | int globalvar = 1; |
1.选择 a栈,b堆,c代码段(常量区),d数据段(静态区)
globalvar存放在:——(数据段) Staticglobalvar存放在:——(数据段)
staticvar存放在:——(数据段) localvar存放在:——(栈)
num1存放在:——(栈)
ch1存放在:——(栈) *ch1存放在:——(栈)
ch存放在:——(栈,那个const修饰的是他指的内容) *ch存放在:——(代码段)
ptr1存放在:——(栈) *ptr1存放在:——(堆)
x存放在:——(栈)
补充:const修饰的是变量里面的内容,和变量存放在那里没有关系
2.C语言中动态内存管理方式malloc,realloc,calloc以及free
1 | int main() |
面试题:
1.realloc、malloc、calloc之间的区别?
malloc和calloc类似,主要是参数和初始化的区别,malloc有一个参数,并且不会初始化。calloc有两个参数,并且会把空间初始化为0。realloc会扩容,如果空间不够,会开辟新空间,并且把旧空间销毁了.
2.malloc的实现原理?
留一个疑问
3.C++内存管理方式
c++有自己的内存管理方式,那就是两个关键字new和delete,但是不要小看这两个关键字,因为他们可以进行一些malloc不能进行的东西,比如说1.对开辟的空间进行初始化 2.返回值不需要进行强制类型转换 3.自定义类型可以自动调用构造函数,也就是说可以将类里面的成员也初始化了
3.1new/delete操作内置类型
1 | int main() |
总结一下:关键字new+类型+个数(一个的话就不用写)+初始化的值(不初始化的话也不需要写)。

补充:调试的时候如何通过数组名访问数组里面的数值呢?数组名+,+数字
3.2new和delete操作自定义类型
对于自定义类型,new开辟空间以后,还会自动调用构造函数,delete会调用析构函数!!!(这个才是new和delete最大的区别所在)
1 | class A |

new,delete,malloc,free除了在调用构造函数和析构函数有区别外,还有一个区别就是malloc在申请失败时返回的是空,而new则是报错。
1 | int main() |

malloc不会直接报错,然而new如果申请失败会抛出异常,需要用try和catch捕捉。
1 | int main() |

有一个小技巧,我们如何调试到那个81次的错误呢?我们可以使用打断点,手动写一个if条件语句,写一个赋值语句来当做断点
1 |
|
虽然我们可以打断点了,但是那个代码非常的冗余,难看,但是我们又很需要它,我们该怎么办呢?其实可以用#ifdef _DEBUG_RXJ 和#endif包裹住不需要的代码,这样的话在编译过程中,这段代码就不会被编译,只有在使用了define _DEBUG_RXJ的时候,这段代码才会被放出来。
注意:new由两部分工作构成,第一部分是开辟一个类的空间并且把地址返回给指针,第二部分是调用构造函数,如果成员变量里面需要开空间的话,构造函数就会给成员开空间,所以一共进行了两步,开辟了两个空间。delete会先调用析构函数把成员变量开辟的空间销毁,然后再销毁开辟的类的大小的空间。
4.operator new和operator delete函数
operator new是对malloc的封装,它与malloc的不同就是他在失败的时候会抛异常,new则又是operator new的封装,new在开辟自定义类型空间时会调用构造函数
operator delete是对free的封装。delete与operator delete不同的是,delete会先调用析构函数,先释放给成员变量开辟的空间,然后再释放new开辟的空间。
所以new先开空间,构造函数再开辟自己的空间。delete先调用析构函数释放成员的空间,然后再销毁new本身开辟的空间
提问:new和free可以混合使用吗?在你掌握原理以后其实可以的(比如说内置类型),但是最好不要乱搞。
补充一点:
A* a = new A [10];
那么编译器一共会开辟过少个字节呢?其实是4+10*sizeof(A);
为什么呢?
其实他还开批了一个空间去存放int类型的10,这一步是为了在调用delete[]时知道开辟了多少字节。
总结一下:
new对应的就是delete,因为此时delete只调用一次析构函数new X[]对应的是delete[],因为new在开辟空间的时候会多开辟一个整型用来存放开辟的类型的个数,delete[]就知道要往前4个字节去寻找要调用几次析构函数。但是如果你没有生成析构函数,那么new就不会多开辟空间去告诉delete调用几次析构函数。所以尽可能去匹配使用

5.定位new的表达式
定位new的作用:显示的调用构造函数(首先我们要知道构造函数是不能显示调用的)。
使用格式:new(指针)+类型
定位new一般配合着内存池使用。如果是自定义类i小姑娘的对象,需要使用new的定义表达式进行初始化
6.malloc、new、free、delete的区别
一、用法方面
1.malloc和free是函数,new和delete是操作符
2.malloc需要自己计算空间的大小。new只需要加上类型,如果要开辟多个对象,用[]加上数字
3.malloc申请的空间不能初始化,而new开辟的空间可以初始化
4.malloc的返回值是void*,而new的返回值就是他本身后面跟的类型的指针
5.malloc在开辟失败的时候会返回nullptr,而new则是抛异常
二、功能方面
1.申请自定义类型的对象时,malloc和free只会开辟空间,不会调用构造函数和析构函数,而new和delete会自动调用构造函数和析构函数。
