当前位置: 首页 > article >正文

【C++系列】-----------内存管理

c++内存管理(涉及:数据在内存中的分布、new和delete使用、动态内存管理等)

文章目录

  • c++内存管理(涉及:数据在内存中的分布、new和delete使用、动态内存管理等)
  • 前言
  • 一、C/C++内存分布
  • 二、C++中动态内存管理
    • 2.1、 new/delete操作内置类型
    • 2.2、 new和delete操作自定义类型
  • 总结


前言

众所周知,c++没有提供(垃圾)回收机制,所以写C/C++程序常常会面临内存泄漏等问题,但是c++提供了对内存精细控制的方式,允许程序员以动态和手动的方式分配和释放内存。这种能力既带来强大的灵活性,也伴随着一定的挑战。下面我们一起看一下如何使用这些方法。


一、C/C++内存分布

下面我们通过一些经典例题来了解一些

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
    static int staticVar = 1;
    int localVar = 1;

    int num1[10] = { 1, 2, 3, 4 };
    char char2[] = "abcd";//比较特殊,仔细阅读一下
    const char* pChar3 = "abcd";
    int* ptr1 = (int*)malloc(sizeof(int) * 4);
    int* ptr2 = (int*)calloc(4, sizeof(int));
    int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
    free(ptr1);
    free(ptr3)
}

1、选择:A、栈 B、堆 C、数据段(静态区) D、代码段(常量区)

globalVar在哪里?____ staticGlobalVar在哪里?____
staticVar在哪里?____ localVar在哪里?____
num1 在哪里?____
char2在哪里?____ *char2在哪里?___
pChar3在哪里?____ *pChar3在哪里?___

通过上面代码我们可以看到:
glovalVar是在Test函数体外创建的变量,即为全局变量,存放在数据段(静态区)中。
变量staticGlobalVar,也处在函数体之外,同时被关键字static修饰,即为全局静态变量,存放在数据段(静态区)中。
staticVar是在Test函数内部创建的静态变量,即为局部静态变量,存放在数据段(静态区)中。
localVar是在Test函数内部创建的变量,即为局部变量,存放在栈区。
num1是在Tese函数内部创建的数组的数组名,即为局部创建的多个普通变量,存放在栈区。
char2是在Test函数内部创建的数组的数组名,同num1。
、* char2是比较特殊的,因为char char2[] = “abcd”;这句代码的实质是用右边的字符串初始化数组(存储在栈中),在代码段(常量区)中有“abcd\0”字符串,拷贝一份存储在char2数组中(abcd只是一份拷贝对象,所占空间还是栈上开辟的)因此 * char2存放在栈中。
pChar3是在Test函数内部创建的const修饰的常指针变量(这里拓展个知识:const在修饰指针时,在*之前修饰,是指 指针指向的),实质还是一个局部创建的变量,只是该变量的值不能修改,因此pChar3存放在栈区。
*pChar3是对数组的的首元素进行解引用,*pChar3是常量字符串的第一个字符,字符常量存放在代码段(常量区)。
*ptr1是对数组的的首元素进行解引用,ptr1是通过动态开辟的空间,动态开在堆区申请空间,因此ptr1存放在堆区。
在这里插入图片描述
说明

  1. 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(了解一下)
  3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
  4. 数据段–存储全局数据和静态数据。
  5. 代码段–可执行的代码/只读常量

二、C++中动态内存管理

c语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

2.1、 new/delete操作内置类型

 void Test()
 {
     // 用法上,比malloc更简洁,不需要计算类型大小,并且可以对空间内容初始化(这点对内置类型还不太明显)
	int* p = (int*)malloc(sizeof(int));
    int* ptr4 = new int;
     // 动态申请一个int类型的空间并初始化为10
     int* ptr5 = new int(10);
     
     // 动态申请10个int类型的空间
     int* ptr6 = new int[10];
     // 动态申请10个int类型的空间,并将他们初始化
     int* ptr7 = new int[10]{1,2,3,4,5,6,7,8,9,10};
     delete ptr4;
     delete ptr5;
     delete[] ptr6;
     delete[] ptr7;
     free(p);
     }

在这里插入图片描述

2.2、 new和delete操作自定义类型

class A
 {
 public:
 A(int a = 0)
 : _a(a)
 {
 cout << "A():" << this << endl;
 }
 ~A()
 {
  cout << "~A():" << this << endl;
 }
 private:
 int _a;
 };
 int main()
{
	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	free(p1);
	A* p2 = new A(1);
	delete p2;
	return 0;
}

函数malloc()、free()与关键字new、delete最大的区别是,new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数,而malloc函数仅会开辟与自定义类型(A)等大字节的空间,并不会完成初始化工作。

总结

这次的博客就到这了,本来计划将new/delete的使用和底层讲一下的,但是篇幅过长,阅读起来会烦躁。


http://www.kler.cn/a/371722.html

相关文章:

  • Python中的数据可视化:Matplotlib基础与高级技巧
  • fmql之Linux以太网
  • Flume采集Kafka数据到Hive
  • Apache POI—读写Office格式文件
  • 简单认识redis - 12 redis锁
  • C#版的有道智云对话接口
  • 手机备忘录怎么导出到电脑,
  • Python自动化测试一文详解
  • 利索能及:全球专利信息尽在掌握,轻松实现专利保护
  • 微服务分布式事务
  • 带哨兵的单向链表(改动版)
  • Zookeeper 理论基础
  • 10.22.2024刷华为OD C题型(三)--for循环例子
  • 使用SpringCloudSleuth和Zipkin进行分布式链路跟踪
  • linux驱动—在自己的总线目录下创建属性文件
  • 微信小程序live-pusher和video同时使用,video播放声音时时大时小
  • qemu-9.1+linux-kernel-6.11+busybox-1.36.1+NFS挂载
  • Java设计模式—观察者模式详解
  • 问题排查思路
  • 记录一次mmpretrain训练数据并转onnx推理
  • 流刷新定位
  • Ubuntu24.04配置samba共享
  • 微服务的雪崩问题
  • 提问GPT
  • 流媒体协议.之(RTP,RTCP,RTSP,RTMP,HTTP)(三)
  • SpringBoot 下的Excel文件损坏与内容乱码问题