当前位置:首页 » 《随便一记》 » 正文

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

14 人参与  2024年11月13日 14:42  分类 : 《随便一记》  评论

点击全文阅读


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存放在堆区。
在这里插入图片描述
说明

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

二、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://zhangshiyu.com/post/185584.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1