new/delete内存分配操作符

news2025/2/24 15:31:20

目录

一、C/C++的内存分布

二、new与delete操作符

1.new/delete 的使用

2.new申请失败抛异常

3.new/delete操作内置类型

4.new/delete 操作自定义类型 

三、operator new与operator delete函数

四、new和delete的实现原理

1.对于内置类型

2.对于自定义类型

①new的实现原理

②delete的实现原理

③new T[n] 的实现原理

④delete[] 的实现原理

五、定位 new 表达式(placement new)

六、面试题

1. malloc/free和new/delete的区别

2. 内存泄漏

①内存泄漏的体现

②内存泄漏分类


 

一、C/C++的内存分布

C/C++在内存分布这块是相同的

54de3f1b88884f959260623ea17850f9.png

栈由高地址向低地址增加

堆于数据段的末端向高地址增加

数据段通常包括三个部分:BSS、已初始化的数据段和只读数据段BBS(未初始化数据段)是一块未初始化的内存区域(例如:static int i 未指定值会被分配至数据段),用于存储全局变量和静态变量,它的内容在程序启动时被设置为0或者为空。在可执行文件中,BSS段通常表示为一个有固定大小的区块,并且在程序加载时会被分配对应的内存空间。

 

二、new与delete操作符

C语言内存管理方式在C++中可以继续使用,但是C++中new和delete运算符还可提供一些高级功能,例如支持类和对象的构造和析构函数。

new/delete 不适用于realloc的内存分配。

1.new/delete 的使用

【new】


分配一个新的内存块

new type;

分配动态分配数组

new type[size];

【delete】

——只能释放由new创建的内存块

删除单个分配的内存块

delete pointer_variable;

删除动态分配的数组(分配的内存块)

delete[] pointer_variable;

 

2.new申请失败抛异常

在 C++ 中,使用 new 运算符申请内存时,如果内存不足,会抛出 std::bad_alloc 异常。因此,在使用 new 运算符申请内存时,为了避免程序崩溃,我们需要使用 try-catch 块来捕获可能抛出的异常具体来说,可以在申请内存的语句前面加上 try,然后在 catch 块中处理异常,如打印错误信息、释放之前申请的内存等,以确保程序可以正常运行。

以下是一个示例:

try {
    int* ptr = new int[100];
    // 申请内存成功,进行后续操作
} catch (const std::bad_alloc& e) {
    std::cerr << "Memory allocation failed: " << e.what() << std::endl;
    // 处理异常,如打印错误信息或释放之前申请的内存
}

需要注意的是,即使你的程序没有显式使用 try-catch 块来捕获 std::bad_alloc 异常,在发生内存不足时,操作系统也会自动向程序抛出 SIGSEGV 信号,导致程序崩溃。因此,为了保证程序的健壮性,建议在使用 new 运算符时始终使用 try-catch 块来捕获可能的异常。

 

3.new/delete操作内置类型

代码如下:

	int* p1 = new int;

    //通过列表初始化,可对分配到的内存直接初始化
	int* p2 = new int(9);
	int* pa1 = new int[10];

    //通过列表初始化,可对分配到的内存直接初始化
	int* pa2 = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	cout << *p2 << endl;
	for (int i = 0; i < 10; ++i)
	{
		cout << pa2[i] << " ";
	}
	cout << endl;
	delete p1;
	delete p2;
	delete[] pa1;
	delete[] pa2;

输出:

9
0 1 2 3 4 5 6 7 8 9

操作符 new/delete 和函数 malloc/free 针对内置类型没有任何差别,只是用法不一样。

 

4.new/delete 操作自定义类型 

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,但是,使用malloc和free来分配和释放内存时,不会调用该类型的构造函数和析构函数。

 

三、operator new与operator delete函数

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70

new 和 delete 是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间, delete 在底层通过operator delete全局函数来释放空间。

实际上 operator new 和 operator delete 的用法跟 malloc 和 free 是完全是一样的功能,都是在堆上申请释放空间,但是失败了处理方式不一样,malloc失败返回NULL,operator new失败以后抛异常。

以下三种方式开辟空间和释放空间的效果是一样的

 

	int* p1 = (int*)malloc(sizeof(int));      //malloc和free
	free(p1);

	int* p2 = new int;                        //new和delete
	delete p2;

	int* p3 = (int*)operator new(sizeof(int));//operator new与operator delete
	operator delete (p3);

 

四、new和delete的实现原理

1.对于内置类型

如果申请的是内置类型的空间,new 和 malloc,delete 和 free 基本类似,不同的地方是:new/delete 申请和释放的是单个元素的空间,new[] 和 delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常,malloc会返回NULL。

 

2.对于自定义类型

假设自定义类型为T 

①new的实现原理

  • 调用 operator new 函数申请内存空间。
  • 调用类型T的构造函数,初始化对象。
  • 返回指向已分配的内存空间的指针。

②delete的实现原理

  • 调用类型 T 的析构函数,释放对象占用的资源。
  • 调用 operator delete 函数释放内存空间。

③new T[n] 的实现原理

  • 调用 operator new[] 函数申请 n 个对象所需的内存空间。
  • 对于每个对象,调用类型 T 的构造函数,初始化对象。
  • 返回指向第一个对象的指针。

④delete[] 的实现原理

  • 对于每个对象,调用类型 T 的析构函数,释放对象占用的资源。
  • 调用 operator delete[] 函数释放内存空间。

 

五、定位 new 表达式(placement new)

定位 new 表达式(placement new)是一种特殊的 new 表达式,它允许我们将对象构造在指定的内存地址上

使用场景:
这种方式通常用于特定的场景,比如在某些嵌入式系统中需要将对象构造在固定的内存地址上,或者需要管理自己分配的内存池等等。

 

new (pointer) type (arguments)

其中,pointer 是一个指向已分配的内存块的指针,type 是对象的类型,arguments 是传递给 type 构造函数的参数。

 

注意事项:

使用定位 new 表达式时,我们必须保证 pointer 指向的内存块已经被正确地分配,并且能够容纳 type 类型的对象。

 

示例如下:

//...
class MyClass {
public:
    MyClass(int val) : m_value(val) {
        cout << "Constructing MyClass object with value " << m_value << endl;
    }

    ~MyClass() {
        cout << "Destructing MyClass object with value " << m_value << endl;
    }

private:
    int m_value;
};

    //...

    // 分配一块内存
    char* buffer = new char[sizeof(MyClass)];

    // 在分配的内存上构造对象
    MyClass* pObject = new (buffer) MyClass(42);

    // 手动销毁对象
    pObject->~MyClass();

    // 释放分配的内存
    delete[] buffer;

在这个例子中,我们首先使用 new char[] 表达式分配了一块内存,然后使用定位 new 表达式在这块内存上构造了一个 MyClass 对象。最后,我们手动调用了析构函数来销毁对象,并使用 delete[] 表达式释放了分配的内存。

 

六、面试题

1. malloc/free和new/delete的区别

共同点:

  • 都是从堆上申请空间,并且需要用户手动释放。

不同点:

  • malloc和free是函数,new和delete是操作符
  • malloc申请的空间不会初始化,new可以初始化。
  • malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型。
  • malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  • 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。
     

2. 内存泄漏

①内存泄漏的体现

代码如下:

void MemoryLeaks()
{
    // 1.内存申请了忘记释放
    int* p1 = (int*)malloc(sizeof(int));
    int* p2 = new int;
    
    // 2.异常安全问题
    int* p3 = new int[10];
    Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.
    delete[] p3;
}

异常安全性是指程序在抛出异常后仍能保持正确状态的能力。


②内存泄漏分类

C/C++程序中一般我们关心两种方面的内存泄漏:

堆内存泄漏(Heap Leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
 

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

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prophet学习(四)趋势Changepoints

目录 趋势Changepoints&#xff08;Trend Changepoints&#xff09; Prophet中的自动更改点检测&#xff08;Automatic changepoint detection in Prophet&#xff09; 调整趋势灵活性&#xff08;Adjusting trend flexibility&#xff09; 指定变更点的位置&#xff08;Spe…

DnCNN-pytorch版本代码运行环境配置

一、DnCNN-pytorch相关下载 (1)DnCNN-pytorch版本代码下载 https://download.csdn.net/download/qq_41104871/87457414 (2)GPU版本的torch0.4.1下载 https://download.csdn.net/download/qq_41104871/87658469 (3)相对应的torchvision0.2.1下载 https://download.csdn…

Redis多级缓存搭建(结合案例学习)

文章目录一. JVM进程缓存1. 在docker中安装Mysql服务2. 向数据库中导入数据和导入案例代码3. 在dokcer中部署nginx服务器实现方向代理4. 在nginx目录下导入主页面5. 配置nginx实现反向代理6. 初步认识Caffine7. 使用Caffeine实现本地进程缓存8. 总结二. LUA语法1. 初识Lua2. 基…

TCP并发服务器模型

文章目录1. 循环服务器2. 并发服务器2.1 多进程并发服务器2.2 多线程并发服务器3. 基于TCP的文件传输服务(目前只有下载)1.tftp下载模型2.TFTP通信过程总结3.tftp下载协议分析1. 循环服务器 一次只能处理一个客户端&#xff0c;等这个客户端退出后&#xff0c;才能处理下一个客…

vue大坑:v-for的key以及props传参不当导致的闭包

为什么props传参在模版中使用没问题&#xff0c;在函数中使用不变化 场景 当我们点击上方的月份时&#xff0c;会改变下方加载的卡片信息 代码&#xff1a; 父组件&#xff1a; <divv-for"(item, index) in vocalStore.getCardMonthData":key"index"…

电梯导航案例

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>小兔鲜儿 - 新鲜 惠民 快捷!</title><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"render…

WPS关闭不了后台一直运行的解决办法(wpscloudsvr.exe)

问题描述 前几天&#xff0c;发现每次打开wps时机箱风扇就转得厉害&#xff0c;把WPS界面叉掉后&#xff0c;桌面的任务栏—就是桌面最下面得黑框框—显示Windows图标和时间日期的那个地方也没有WPS任务&#xff0c;但是机箱还是响的厉害&#xff0c;检查了任务管理器发现一直…

SpringBoot自动配置的原理是什么?

自动配置的核心就在SpringBootApplication注解上&#xff0c;SpringBootApplication这个注解底层包含了3个注解&#xff0c;分别是&#xff1a; SpringBootConfiguration ComponentScan EnableAutoConfiguration EnableAutoConfiguration这个注解才是自动配置的核心。 它封…

速Raysync v6.6.8.0版本发布

最近镭速发布了v6.6.8.0版本&#xff0c;已经发布上线了。主要更新内容有服务器下发任务支持指定客户端&#xff0c;客户端增加日志清理和日志压缩&#xff0c;自动删除源文件保持源目录结构&#xff0c;支持将文件投递给其他成员等功能&#xff0c;详细的更新内容如下&#xf…

Flink DataStream读写Hudi

一、pom依赖 测试案例中&#xff0c;pom依赖如下&#xff0c;根据需要自行删减。 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-ins…

HTML+CSS+JS 学习笔记(一)———HTML(下)

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;前端 &#x1f331;往期回顾&#xff1a;HTMLCSSJS 学习笔记&#xff08;一&#xff09;———HTML(上) HTMLCSSJS 学习笔记&#xff08;一&#xff09;———HTML(中) &#x1f618;博客制作不易…

Linux工具——gcc和gdb

&#x1f3c0;博主主页 &#x1f3c0;gitee主页 目录&#x1f3c0;Linux编译器-gcc⚽️gcc使用⚽️函数库&#x1f3c0;Linux调试器-gdb⚽️简介⚽️gdb使用&#x1f3c0;Linux项目自动化构建工具-make/Makefile⚽️简介⚽️依赖关系⚽️make/Makefile实现原理⚽️项目清理&…

证明电压电流相位差的余弦值和功率因数相等

证明&#xff1a;“电压电流相位差的余弦值”和“功率因数”相等。 电压电流相位差的余弦值和功率因数相等&#xff0c;这在《电路分析》中给出过结论&#xff0c;但没有给出详细的证明过程。其次&#xff0c;在电气工程师考试中&#xff0c;也会经常遇到。 电压电流相位差&am…

【Linux】虚拟机的克隆

【想要克隆虚拟机&#xff0c;被克隆的虚拟机必须是关机状态&#xff1b;】 一、克隆虚拟机 1、右击想要克隆的虚拟机 2、进入到这个页面后点击“下一步” 3、进入到这个页面后点击“下一步” 4、进入这个页面后选“创建完整克隆”&#xff0c;再点击下一步 5、最好将位置改成…

入门IC必读书目,你想知道的都在这里

在IC行业&#xff0c;技术和经验都很重要&#xff0c;为了更好的学习&#xff0c;现为大家整理了各岗位的学习书目。 通用基础类 《半导体物理学》 这本书被国内大部分高校都采用为半导体物理课程的教材。同时&#xff0c;也是部分高校推荐使用的微电子专业硕士生初试参考书。…

【cmake学习】搭建一个简单的cmake工程(优化版)

之前搭建了一个基本的cmake工程&#xff0c;仅使用了一个 CMakeLists.txt 文件来管理整个工程&#xff0c;实际上一个工程里可以包含多个 CMakeLists.txt 文件&#xff0c;这样做的目的是把引入所需文件、生成执行文件/库文件 这两个工作交由两个 CMakeLists.txt 分别实现。 【…

接口自动化【一】(抓取后台登录接口+postman请求通过+requests请求通过+json字典区别)

文章目录 前言一、requests库的使用二、json和字典的区别三、后端登录接口-请求数据生成四、接口自动化-对应电商项目中的功能五、来自postman的代码-后端登录总结前言 记录&#xff1a;json和字典的区别&#xff0c;json和字段的相互转化&#xff1b;postman发送请求与Python…

Python:清华ChatGLM-6B中文对话模型部署

1、简介 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&#xff0…

SpringBoot程序运行时动态修改主数据库配置(不需要改配置,不需要重启)

SpringBoot程序运行时修改主数据库配置&#xff08;不需要改配置&#xff0c;不需要重启&#xff09;搞事背景心路历程搞事背景 在面试某家单位的时候&#xff0c;碰到了一家单位线上考试&#xff0c;要求开发一个springboot后台。一眼看去都是正常的需求&#xff0c;突然我在…

Raft: 基于 Log 复制的共识算法

References Raft 演示 In Search of an Understandable Consensus Algorithm (Extended Version) 1. Raft 是什么 1.1 目标: 复制 Log 在讲解 Raft 协议的具体行为之前我们需要明白 Raft 的目标是什么&#xff1f;在一些情况下我们需要保证分布式集群中的机器拥有相同的数…