【C++】C\C++内存管理

下面是围绕C\C++内存管理这一块知识谈论相关的内存管理机制,有需要借鉴即可。

同时,我在下面也放了快速建立链表的模板,方便oj题目拿到vs上进行调试。

在介绍本节博客之前,请思考为什么要进行内存划分?或者说内存为什么要划分为不同的区域?直接一整块使用多好。

答案是为了方便内存管理。这就类似于我们为什么要对全国进行划分不同给的省份?正是因为划分了不同的省份可以方便管理才这样做的。
在这里插入图片描述

1.CPP内存管理

针对于C/CPP语言,我们一般将内存划分为如下几个不同的区域:
在这里插入图片描述
注:语言层面名称:静态区、常量区
操作系统层面名称:数据段、代码段

请回答下面代码中的变量分别存储在计算机内存的哪个区域?

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);
}

在这里插入图片描述
下面是答案:

在这里插入图片描述

对于上面所介绍的这些内存空间,我们作为编写代码的人应该重点关注哪一块区域呢?
答:
是堆空间,因为堆是系统把一部分操作权限给到我们编写代码的人的,包括一些堆的空间申请,堆的空间释放…

在C语言中,我们常用malloc\realloc\calloc进行对堆空间的申请和free释放
因而想要使用堆空间,下面代码基本说是"必经之路"。

思考:malloc、realloc、calloc的区别?
答:
malloc:申请一块空间
realloc:更改空间大小,支持原地扩容和异地扩容
calloc:申请一块空间并初始化

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}

我们申请一块空间是需要先把地址放到一个指针变量里,然后再进行检查…程序复杂且重复。
CPP为了解决这个问题,通过对malloc函数进行封装加工处理,形成了new关键字,通过对free函数的封装加工处理,形成了delete关键字。

1.1new、delete关键字概念

CPP提供的new与delete相对于C语言中的malloc与free的提升主要集中在两个方面,一是用法更加简单,二是功能更加强大

1.2特性

  • 1.用法上,更加简单

    • new关键字替代了malloc(sizeof())和检查那一大堆
      在这里插入图片描述
  • 2.功能上,更加强大

    • ①开始:可以支持在开辟空间时候初始化
      在这里插入图片描述

    • ②创建过程:可以支持自定义类型的空间开辟,new自动调用构造函数,delete自动调用对应的析构函数(重点)
      在这里插入图片描述

    • ③结束:new失败了会抛异常,不用指针检查是否为空

1.3总结

在这里插入图片描述

从上面看来,new和delete的语法引入大大方便了我们对堆空间的使用。那其底层是如何实现的呢?

2.new、delete的底层

2.1new的底层是operator new:

new —>operator new + n次构造函数(自定义类型) —>malloc
new[] —> operator new[] —> operator new + n次构造函数(自定义类型) —> malloc

我们以下面代码为例,看其汇编解析其底层:
在这里插入图片描述
在这里插入图片描述

思考:为什么要定义operator new对malloc实现封装?
答:
①要实现new失败要抛异常
②要调用自定义类型的构造函数

思考:直接new空间,编译器是怎么确定要开多大空间的?C语言中我们需要给空间大小的。
答:通过sizeof编译时进行计算,sizeof是一种运算符,其在编译期间确定,而不是在运行时。

思考:为什么上面自定义类型开空间多开8个字节的空间?
答:主要是多开几个字节的空间来存储这块空间多大,方便下一步delete释放时候要释放多少空间。
在这里插入图片描述

注:下图蓝色区域是新开空间存储相关内容的空间区域,红色则是存储这块空间是多大的,方便delete的删除操作。
在这里插入图片描述

2.2delete的底层是operator delete

delete —> 析构函数 + operator delete —> free
注意:有些delete[]会进一步调用operator delete

思考:operatr delete是先调用析构函数还是先调用free?
答:先调用析构函数
在这里插入图片描述

创建与销毁一定要对等使用,即:

  • 开辟空间:new[] ,释放空间:delete[]
  • 开辟空间:new,释放空间:delete

思考:为什么?
在这里插入图片描述

2.3总结

在这里插入图片描述

3.内存泄漏

3.1概念

是指一块内存空间申请了不用却也不还给系统。

共分为两种情况:

  • 1.堆内存泄露
    堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
  • 2.系统资源泄露
    指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

4.快速生成链表模板

#include<iostream>
using namespace std;

struct ListNode
{
	int _val;
	ListNode* _next;

	//构造函数初始化
	ListNode(int val = 0)
		:_val(val)
		, _next(nullptr)
	{}
};

ListNode* CreatList(int n)
{
	ListNode head(-1);//生成一个类对象
	ListNode* tail = &head;//尾指针

	int val;
	printf("请依次输入%d个节点的val值:>\n", n);

	for (int i = 0; i < n; i++)
	{
		//cin >> val;
		val = i;
		tail->_next = new ListNode(val);
		tail = tail->_next;
	}

	return head._next;
}

void test2()
{
	ListNode* head = CreatList(100);
	ListNode* pcur = head;
	for (int i = 0; i < 100; i++)
	{
		cout << pcur->_val << "  ";
		pcur = pcur->_next;
	}
}

EOF

  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在C++中,智能指针是一种用于管理动态内存的工具。 C++提供了三种智能指针:shared_ptr,unique_ptr和weak_ptr。 这些智能指针的共同点是,它们在指向的地址引用计数为0后会自动释放内存。 shared_ptr是一种引用计数智能指针,它允许多个指针同时指向同一块内存。 它会维护一个引用计数,每当创建或复制shared_ptr时,引用计数会增加。 当引用计数降为0时,shared_ptr会自动删除所指向的对象。 unique_ptr是一种独占智能指针,它确保只有一个指针可以指向内存。 当unique_ptr被销毁或重置时,它会自动删除所指向的对象。 由于它是独占的,因此unique_ptr不支持多个指针指向同一块内存。 在C++中,用new运算符分配内存,用delete运算符释放内存,而malloc函数分配内存,free函数释放内存。 与new/delete相比,malloc/free是C语言中用于动态内存管理的函数。 new/delete是C++中的对应操作。 区别在于,new/delete是运算符,而malloc/free是函数。 此外,new/delete会自动调用构造函数和析构函数,而malloc/free则不会。 当我们使用new来分配内存时,需要手动调用析构函数来释放资源,而使用malloc分配的内存则需要手动使用free函数来释放。 总结一下,C++中的智能指针提供了更方便且更安全的内存管理方式。 shared_ptr允许多个指针共享内存,unique_ptr确保只有一个指针指向内存,并在离开作用域时自动释放,而malloc和free是C语言中的动态内存管理函数,需要手动管理内存的分配和释放,并不会自动调用构造函数和析构函数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++ - 智能指针及其内存管理](https://blog.csdn.net/Tracker647/article/details/122391367)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值