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

13.C++内存管理2(C++ new和delete的使用和原理详解,内存泄漏问题)

⭐本篇重点:new, delete的使用和原理

⭐本篇代码:c++学习/04.c++-动态内存管理 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)

目录

一. new和delete的使用

1.1 操作内置类型

1.2 操作自定义类型

二. new, delete与malloc, free的区别

2.1 相同点

2.2 不同点

三. new/delete原理(operator new 和 operator delete)

3.1 函数operator new / operator delete

3.2 new 和 delete 原理

四. 内存泄漏问题

4.1 什么是内存泄漏?内存泄漏的危害是什么?

4.2 内存泄漏的原因

4.3 避免内存泄漏

五. 下篇文章:STL简介


一. new和delete的使用

        new和delete是C++提供的一对操作符,可以完成对内存的管理。常用于完成内置类型和自定义类型的初始化

        其中,new用于开辟空间,delete使用释放空间

1.1 操作内置类型

#include <iostream>
using namespace std;

int main()
{
	//1.new申请一个int型的变量,并将其赋值为999
	int* a = new int(999);
	
	//2.new申请10个int型的变量
	int* nums = new int[10];
	for (int i = 0; i < 10; i++)
	{
		nums[i] = i;
	}

	cout << *a << endl;

	for (int i = 0; i < 10; i++)
	{
		cout << nums[i] << " ";
	}

	//释放申请的空间
	delete a;
	delete[] nums;
	return 0;
}

分析:我们申请了并初始化一个变量a,以及一个数组nums。然后输出它们的值。运行结果如下:

要注意new和delete的搭配使用

new和delete用于开辟和释放一个元素。

new 类型[]  和 delete[] 用于开辟和释放连续的空间。

1.2 操作自定义类型

new和delete还能够操作自定义类型。

new初始化自定义类型的时候会调用其 构造函数

delete释放自定义类型的时候会调用其 析构函数

#include <iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "调用A的构造函数" << endl;
	}

	~A()
	{
		cout << "调用A的析构函数" << endl;
	}

	void print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p1 = new A;
	p1->print();

	A* p2 = new A(1);
	p2->print();

	A* p3 = new A[5]; //初始化连续的变量

	delete p1;
	delete p2;
	delete[] p3;
	return 0;
}

运行结果如下:

二. new, delete与malloc, free的区别

2.1 相同点

new/delete 与 malloc/free 都是在堆上开辟空间,并且需要用户手动释放空间

2.2 不同点

new/delete是C++提供的操作符,malloc/free是C语言提供的库函数

new/delete申请空间会对其进行初始化,malloc/free不会进行初始化

new/delete申请空间会调用其构造函数,释放空间会调用析构函数,malloc/free 申请释放空间不会调用构造函数和析构函数

举例:

#include <iostream>
using namespace std;

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "调用A的构造函数" << endl;
	}

	~A()
	{
		cout << "调用A的析构函数" << endl;
	}

	void print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};

int main()
{
	//new/delete申请空间会初始化
	cout << "new/delete" << endl;
	A* p1 = new A;
	delete p1;

	//malloc/free申请空间不会初始化
	cout << "malloc/free" << endl;
	A* p2 = (A*)malloc(sizeof(A));
	if (NULL == p2)
	{
		cout << "malloc error!" << endl;
		exit(1);
	}
	free(p2);
	p2 = NULL;

	return 0;
}

        malloc申请空间的时候,我们需要将返回的 void* 强制转化为我们需要的类型,并且需要计算我们需要申请的空间,还需要处理返回值为NULL的情况。

        new申请空间不需要强转,不许计算大小直接在后面放我们需要申请的空间类型即可,申请多个变量带上[]即可!不过使用new的时候需要捕获异常

三. new/delete原理(operator new 和 operator delete)

3.1 函数operator new / operator delete

        new/delete是用于动态申请和释放空间的操作符,而operator new 和 operator delete是系统提供的全局函数      

          new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。

 operator new 和 operator delete的部分源码如下

//operator new: 该函数通过malloc申请空间
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
     if (_callnewh(size) == 0)
     {
         // report no memory
         // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
         static const std::bad_alloc nomem;
         _RAISE(nomem);
     }
return (p);
}


//operator delete: 该函数最终是通过free来释放空间的
void operator delete(void *pUserData)
{
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
         return;
     _mlock(_HEAP_LOCK);  /* block other threads */
     __TRY
         /* get a pointer to memory block header */
         pHead = pHdr(pUserData);
          /* verify block type */
         _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
         _free_dbg( pUserData, pHead->nBlockUse );
     __FINALLY
         _munlock(_HEAP_LOCK);  /* release other threads */
     __END_TRY_FINALLY
     return;
}

//free的实现
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

所以我们知道:operator new这个函数 是通过malloc来申请空间的。申请失败的时候会抛出异常,operator delete是通过free来实现释放空间的

3.2 new 和 delete 原理

对于内置类型,new/delete和malloc/free相似。区别见本篇2.2

对于自定义类型:

new原理:

        调用函数 operator new 申请空间,然后在申请的空间上调用构造函数完成对象的构造和初始化

delete原理:

        先在申请的空间上调用对象的析构函数进行清理,然后调用函数 operator free 进行释放对象的空间

四. 内存泄漏问题

4.1 什么是内存泄漏?内存泄漏的危害是什么?

        内存泄漏是因为程序员的疏忽和错误,没有去释放不再使用的内存空间。内存泄漏不是物理内存的消失,而是应用程序分配某段内存后,因为错误设计,导致程序失去了对这段内存的控制,造成空间浪费

        内存泄漏的危害:长期运行的程序出现内存泄漏会导致系统越来越卡,直到卡死。

4.2 内存泄漏的原因

        内存泄漏一般分为堆内存泄漏和系统资源泄漏。

堆:当我们使用malloc/new申请空间之后,使用完了却没有使用delete/new去释放这段空间。结果就是这段空间无法使用

系统资源泄露:指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放 掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

4.3 避免内存泄漏

1 要有良好的工程设计和编码规范,申请完空间之后需要匹配释放空间。

2 有时候我们写了释放空间的代码,由于发生了异常导致这段代码没有被执行。这种时候就需要采用RAII思想和智能指针来解决

3 使用内存泄漏检测工具进行检测

五. 下篇文章:STL简介


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

相关文章:

  • 【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
  • OceanBase 驱动类获取数据库精确类型 “Oracle|MySQL”
  • Vue3-后台管理系统
  • 华三(H3C)T1020 IPS服务器硬件监控指标解读
  • 主IP地址与从IP地址:深入解析与应用探讨
  • AUTOSAR_EXP_ARAComAPI的7章笔记(6)
  • 数据结构(双向链表——c语言实现)
  • Restful API 规范详解
  • 单片机学习笔记 2. LED灯闪烁
  • c++--------《set 和 map》
  • C++手写PCD文件
  • 使用Kotlin写一个将字符串加密成short数组,然后可以解密还原成原始的字符串的功能
  • 前端页面自适应等比例缩放 Flexible+rem方案
  • 小程序-基于java+SpringBoot+Vue的超市购物系统设计与实现
  • 【React 进阶】掌握 React18 全部 Hooks
  • 鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
  • 详解八大排序(一)------(插入排序,选择排序,冒泡排序,希尔排序)
  • Linux驱动开发第2步_“物理内存”和“虚拟内存”的映射
  • EDA实验设计-led灯管动态显示;VHDL;Quartus编程
  • Ubuntu24.04LTS设置root用户可远程登录
  • Flutter踩坑记录(一)debug运行生成的项目,不能手动点击运行
  • Qt5-雷达项目
  • C++零基础入门:趣味学信息学奥赛从“Hello World”开始
  • 数字排序的多种方法与实现:从基础到优化
  • 【MyBatis 源码阅读与笔记】Mapper 接口的动态代理实现
  • Python实现随机分布式延迟PSO优化算法(RODDPSO)优化CNN分类模型项目实战