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

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

文章目录


前言

众所周知,c++没有提供(垃圾)回收机制,所以写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操作内置类型

c 复制代码
 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操作自定义类型

c 复制代码
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的使用和底层讲一下的,但是篇幅过长,阅读起来会烦躁。

相关推荐
你有抖音吗12 分钟前
【每日 C/C++ 问题】
开发语言·c++
霁月风1 小时前
设计模式——模板方法模式
c++·设计模式
knighthood20011 小时前
ros中仿真编写launch时robot_state_publisher,output参数
c++·ubuntu·ros
小林熬夜学编程1 小时前
【Linux系统编程】第四十二弹---多线程编程全攻略:涵盖线程创建、异常处理、用途、进程对比及线程控制
linux·服务器·c语言·开发语言·c++
£suPerpanda1 小时前
牛客周赛 Round65 补题DEF
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
code .1 小时前
C++各个版本的主要特性
开发语言·c++·现代c++
玛卡巴卡(努力学习版)2 小时前
矩阵特殊打印方式
c++·算法·矩阵
hope_wisdom2 小时前
C++网络编程之IO多路复用(一)
网络·c++·select·io多路复用
暴怒香菜统治世界2 小时前
数据结构--二叉树_链式(下)
c语言·开发语言·数据结构·算法·链表