C/C++内存管理

1. C/C++内存分布

1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存,做进程间通信。

3. 堆用于程序运行时动态内存分配,堆是可以上增长的。

4. 数据段--存储全局数据和静态数据。

5. 代码段--可执行的代码/只读常量。

提问:图中*char2 *pChar3 在哪里?

*char2位于栈中,*pChar3位于代码段。

2. C语言中动态内存管理方式:malloc/calloc/realloc/free

1.malloc

malloc函数,void *malloc(unsigned int num_bytes);

里面参数代表需要申请多少bit空间。

2.calloc

calloc函数,void *calloc(size_t n, size_t size);

1.第一个参数代表申请类型的个数,第二个参数代表一个类型的大小。

(申请20个int类型空间,会int *p = (int *)calloc(20, sizeof(int))

2.calloc却在申请后,对空间逐一进行初始化,并设置值为0;

3.realloc

realloc函数,void *realloc(void *mem_address, unsigned int newsize);

1.第一个参数是原空间的起始位置,第二个参数要修改到的大小。

(int*a=(int*)malloc(sizeof(int)); int* p=(int*)realloc(a,sizeof(int)*2 );)把a指向的1int的空间扩容到2 int.

2.如果a指针指向的空间后面还有空间足够扩容,会在a后面进行扩容。

3.如果没有a空间后面足够的空间扩容,p会再找一块sizeof(int)*2的空间,把a的内容拷贝过来,并free a;

4.如果找不到就返回null;

如果p3没有找到新空间,那么p2仍存在,需要free;

3.C++内存管理方式

1.new/delete操作内置类型

C++通过new和delete操作符进行动态内存管理。

int main()
{
	int* a = new int;//申请一块int字节的空间
	int* b = new int(1);//申请一块int字节的空间并初始化1
	int* c = new int[10];//申请一块int*10大小的空间
	int* d = new int[10] {1, 2, 3, 4}; //申请一块int*10大小的空间,并初始化(没给值的初始化0)
	delete a;//销毁空间
	delete b;
	delete c;
	delete d;
	return 0;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和 delete[],注意:匹配起来使用。

2.new和delete操作自定义类型

1.new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构 造函数和析构函数

对于自定义类型,malloc申请了空间但不能直接对类的成员变量初始化。

而new可以自动调用默认构造,没有默认构造也可以显式传参进行构造。

对于多参数的构造函数,我们需要把要传的参数用{}括起来。

4. operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符operator new 和operator delete是系统提供的 全局函数new底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

operator new比malloc多了什么?

1.operator new 实际也是通过malloc来申请空间,但malloc申请空间失败的话是返回null,打印错误编号。而operator new申请失败会进行抛异常,打印出更完善的错误信息。

2.operator new 还会调用类的构造函数。

注:在一个栈类,有int*_a,int _top,int _capacity 三个成员变量。而_a 又指向了一块空间。

operator new申请的是3个成员变量的空间,调用的构造函数申请的是_a指向的空间。

operator delete销毁的是3个成员变量的空间,调用的析构函数销毁的是_a指向的空间。

5. new和delete的实现原理

1.内置类型

对于内置类型,new和malloc delete和free没有本质区别。

new delete是申请/消除单个空间。new[ ] delete[ ]是操作多个对象。

new申请失败会抛异常,而malloc失败会返回null。

2 自定义类型

new原理

1.调用operator new函数申请空间。

2.调用构造函数,完成初始化。

delete原理

1.调用析构函数,完成对象中资源清理的工作。

2.调用operator detele函数销毁空间。

new[ n ] 原理

1.调用operator new[]函数,底层仍是调用operator new函数,完成n个对象的申请空间。

2.在申请空间上调用n次构造函数。

detele[ ]原理

1.在申请空间上调用n次析构函数,完成n个对象的中资源清理的工作。

2.调用operator detele[]函数,底层仍是调用operator detele函数释放空间。

6. 定位new表达式(placement-new)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

使用格式: new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针,initializer-list是类型的初始化列表

int main()
{
	A* p1 = (A*)operator new(sizeof(A));//申请空间
    //p1->A(); 构造函数不能直接调用
	new(p1)A; //显式实例化调用 注意:如果A类的构造函数有参数时,此处需要传参

	p1->~A();//析构函数可以直接调用
	operator delete(p1);//销毁对象
	


	//对于多个对象
    //1.先申请一堆空间
	A* p2 = (A*)operator new(sizeof(A) * 10);//不加[]也行
	//2.用for循环一个对象一个对象初始化
	for (int j = 0; j < 10; j++)
	{
		new(p2+j)A(j);
	}
	//new(p2)A[10]{ 1,2,3 };//一般个数少的可以
    //3.用for循环一个对象一个对象完成资源回收
	for (int i = 0; i < 10; i++)
	{
		(p2 + i)->~A();
	}
    //4.最后销毁
    operator delete(p2);//不加[]也行,底层也是调用的operator delete
}

new和delete一定要配对使用吗?

如果成员变量没有资源没有清理,这样看起来好像没什么问题。

为什么对多个自定义对象free会出错呢?

我们可以看出new开辟了48个字节

我们明明开辟10*int 40个字节,为什么编译器会开48个字节呢?

对一块空间需要调用多次析构函数,那么编译器会开8字节(vs2022)+需要开辟的空间。

多开辟的8个空间是用来记录对一块空间需要调多少次析构函数。

从图中可以看出p1前有8个字节,且值为0a(10)。

如果我们用delete p1;来销毁是否可以呢?

可以看出还是出错了。

这是因为只有delete[] p1;才会连同8个计数的字节一起销毁。

从下面的图中就可以看出,delete[]会从p1位置减去8

正是因为编译器多开了8个字节来记录有多少个对象(为了确认调用析构的次数),

delete[ _ ] 才可以不用我们专门传个数。

new A[10];(开辟多个对象)编译器一定会多开字节吗?

这里编译器并没有多开字节记录需要调用析构的次数,因为类中并没有析构函数。

所以这里编译器只开了40字节大小的空间。

结论:建议配对使用。new A[N]和delete[]A new A和delete A malloc和free

7.malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

1. malloc和free是函数,new和delete是操作符

2. malloc申请的空间不会初始化,new可以初始化

3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可

4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常

6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

相关推荐

  1. 内存管理

    2024-04-22 15:42:02       15 阅读
  2. C/C++——内存管理

    2024-04-22 15:42:02       37 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-22 15:42:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-22 15:42:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-22 15:42:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-22 15:42:02       18 阅读

热门阅读

  1. Linux命令学习—Apache 服务器(上)

    2024-04-22 15:42:02       13 阅读
  2. sql~ 将一行转为多行

    2024-04-22 15:42:02       14 阅读
  3. node.js常用指令

    2024-04-22 15:42:02       13 阅读
  4. 美国基金会注册

    2024-04-22 15:42:02       15 阅读
  5. AUTOSAR OS Alarm讲解

    2024-04-22 15:42:02       16 阅读
  6. CentOS常见命令

    2024-04-22 15:42:02       13 阅读
  7. MySQL--数据的增删改

    2024-04-22 15:42:02       15 阅读
  8. Qt的坐标转换

    2024-04-22 15:42:02       13 阅读
  9. 【Flutter】序列化方案之命令行生成model

    2024-04-22 15:42:02       17 阅读