浅谈C/C++的new和delete以及对象池的实现

今天我们来谈谈C++中的new和delete😊😊😊。在软件开发中,常常需要动态地分配和撤销内存空间,C语言中利用库函数malloc和free分配和撤销内存空间的。而在C++中则是 new和delete

  • malloc函数时必须指定需要开辟的内存空间的大小,需要做类型强转
  • malloc开辟内存失败,返回nullptr
  • new 不仅可以做内存开辟(调用构造函数,如果有的话),还可以做内存初始化操作
  • new 开辟内存失败会抛出bad_alloc类型的异常
  • delete 调用析构函数(如果有的话),再调用operator delete,进行free

# malloc、new的使用格式

int *p = (int*)malloc(sizeof(int));  //malloc
if(p == nullptr) return -1;
free(p);int *p1 = new int(20);  //new
delete p1;int *p2 = new int[20](); 
delete[] p2;

# 对于new的使用,有多种方式如下:

int *p = new int(20);  //普通
int *p2 = new (nothrow) int;   //不跑异常
const int *p3 = new const int(40); //常量int data = 2;
int *p4 = new (&data) int(40); //定位new,把指定位置的内存空间对于存储的数据修改

# new 、 delete的底层原理
在new和delete的底层汇编指令上,执行命令时实际上是调用 operator new 和 operator delete 这两个重载函数

在这里插入图片描述
# 重写一遍new / []和 delete / []

void* operator new (size_t size) 
{void* p = malloc(size); //底层还是通过malloc来开辟内存if (p == nullptr) {throw bad_alloc();}cout << "operator new addr: " << p << endl;return p;
}void operator delete(void* ptr)
{cout << "operator delete addr: " << ptr << endl;free(ptr);
}void* operator new[] (size_t size)
{void* p = malloc(size); //底层还是通过malloc来开辟内存if (p == nullptr) {throw bad_alloc();}cout << "operator new[] addr: " << p << endl;return p;
}void operator delete[] (void* ptr)
{cout << "operator delete[] addr: " << ptr << endl;free(ptr);
}int main()
{try{int* p = new int(20);delete p;int* q = new int[10];delete[] q;}catch (const bad_alloc& err) { cerr << err.what() << endl; }return 0;
}

new 和 delete能够混用吗?这里给出一段代码

class Test
{
public:Test(int data = 10){ cout << "Test()" << endl; }~Test() {cout << "~Test()" << endl; }
private:int* ptr;
};int main()
{int* p = new int(20);delete[] p;int* q = new int[10];delete q;Test* pp = new Test();//delete []pp;   //混用delete 和 delete[]delete pp;Test* qq = new Test[5];delete[] qq;//delete qq;  //混用delete 和 delete[]return 0;
}

在这里插入图片描述
我们发现这里对于普通的编译器内置类型,new和delete混用没问题,但是对于对象Test,构造了5次,析构了一次,最后系统崩溃了,why ? ? ? 对于new Test[5]开辟的不只是5个对象的字节,实际上它多开了4个字节用于存储对象的个数,当我们执行delete调用operator delete(void* ptr)时,传入的ptr其实应该是给第一个对象分配内存的地址 - 4,同理对于delete [] pp也会往前找4个字节,而它并不是从它前4个字节的内存上开辟的,会出现问题,即new 和 delete 不能混用
在这里插入图片描述

简单对象池的实现

#include<iostream>
#include<cstring>
using namespace std;template<typename T>
class Queue
{
public:Queue(){_front = _rear = new QueueItem();}~Queue(){QueueItem* cur = _front;while (cur != nullptr){_front = _front->_next;delete cur;cur = _front;}}void push(const T& val){QueueItem* item = new QueueItem(val);_rear->_next = item;_rear = item;}void pop(){if (empty()){return;}QueueItem* first = _front->_next;_front->_next = first->_next;if (_front->_next == nullptr) _rear = _front;delete first;}T front() const { return _front->_next->_data; }bool empty() const { return _front == _rear; }private:struct QueueItem{QueueItem(T data = T()) :_data(data), _next(nullptr) {}// Memory managementvoid* operator new(size_t size){if (_itemPool == nullptr){_itemPool = (QueueItem*)new (std::nothrow) char[Pool_ITEM_SIZE * sizeof(QueueItem)];QueueItem* p = _itemPool;for (; p < _itemPool + Pool_ITEM_SIZE - 1; p++){p->_next = p + 1;}p->_next = nullptr;}QueueItem* p = _itemPool;_itemPool = _itemPool->_next;return p;}void operator delete(void* ptr){QueueItem* p = static_cast<QueueItem*>(ptr);p->_next = _itemPool;_itemPool = p;}T _data;QueueItem* _next;static const int Pool_ITEM_SIZE = 1000000;static QueueItem* _itemPool;};QueueItem* _front; // HeadQueueItem* _rear;  // Tail
};template<typename T>
typename Queue<T>::QueueItem* Queue<T>::QueueItem::_itemPool = nullptr;int main()
{Queue<int> q;for (int i = 0; i < 1000000; i++) {q.push(i);q.pop();}cout << q.empty() << endl;return 0;
}

🌻🌻🌻以上就是浅谈C/C++的new和delete以及对象池的实现的内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻

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

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

相关文章

【vue baidu-map】实现百度地图展示基地,鼠标悬浮标注点展示详细信息

实现效果如下&#xff1a; 自用代码记录 <template><div class"map" style"position: relative;"><baidu-mapid"bjmap":scroll-wheel-zoom"true":auto-resize"true"ready"handler"><bm-mar…

为何虎茅掌柜 短短6个月会员近百万 月销售额破亿!

大家好 我是吴军 一家软件开发公司的产品经理 今天我们来分析一下&#xff0c;一个卖酒的模式 为什么这家平台短短6个月&#xff0c;发展百万名用户&#xff0c;月销售额破亿! 虎茅掌柜&#xff0c;切记这个虎茅和茅台的那个没有任何关系 虎茅掌柜 虎茅掌柜实质上是一种…

Spring Bean的生命周期流程

前言 Java 中的公共类称之为Java Bean&#xff0c;而 Spring 中的 Bean 指的是将对象的生命周期&#xff0c;交给Spring IoC 容器来管理的对象。所以 Spring 中的 Bean 对象在使用时&#xff0c;无需通过 new 来创建对象&#xff0c;只需要通过 DI&#xff08;依赖注入&#x…

2024 MCM数学建模美赛2024年A题复盘,思路与经验分享:资源可用性与性别比例 | 七鳃鳗的性别比例变化对生态系统稳定性的影响(四)

审题 第三问要我们评估七鳃鳗的性别比例变化对生态系统稳定性的影响。 这里我们就要去查一下生态系统稳定性的定义。 通过查资料我们知道&#xff0c;生态系统稳定性包括生态系统的抵抗力和恢复力。 OK&#xff0c;到这里问题就变成了&#xff0c;七鳃鳗的性别比例对生态系…

漏洞复现-H3C系列

漏洞复现-H3C H3C 用户自助服务平台远程命令执行漏洞H3C堡垒机H3C防火墙 admin/adminH3C root/h3c123.com【漏洞复现】华三用户自助服务产品dynamiccontent.properties.xhtml接口处存在RCE漏洞H3C交换机H3C cas_cvm_upload-RCE (默认写入冰蝎4.0. 3aes)H3C CVM任意文件上传漏洞…

Java 根据IP获取IP地址信息(离线)

<!-- https://mvnrepository.com/artifact/org.lionsoul/ip2region --><dependency><groupId>org.lionsoul</groupId><artifactId>ip2region</artifactId><version>2.7.0</version></dependency> 地址&#xff1a;http…

【计算机网络】1.5 分组交换网中的时延、丢包和吞吐量

A.分组交换网中的时延 当分组从一个节点沿着路径到后一节点时&#xff0c;该分组在沿途的各个节点经受了几种不同类型的时延。 时延的类型 处理时延 - d n o d a l d_{nodal} dnodal​ 处理时延包括以下部分—— a. 检查分组首部 b. 决定分组导向 排队时延 - d p r o c d_{…

算法基础杂项

目录 1算法最优解 2.时间复杂度排序 3.对数器 1算法最优解 1.首先&#xff0c;保证时间复杂度最低 2.其次&#xff0c;保证空间复杂度最低 3.常数项低不低&#xff0c;一般没人管 2.时间复杂度排序 3.对数器 import java.util.Arrays;public class Test {public static …

Elasticsearch使用Kibana进行基础操作

一、Restful接口 Elasticsearch通过RESTful接口提供与其进行交互的方式。在ES中&#xff0c;提供了功能丰富的RESTful API的操作&#xff0c;包括CRUD、创建索引、删除索引等操作。你可以用你最喜爱的 web 客户端访问 Elasticsearch 。事实上&#xff0c;你甚至可以使用 curl …

Autoware.auto源码安装

自 2022 年以来&#xff0c;已将 Autoware 的开发迁移到 GitHub。目前Auto版本并没有进行最新维护 一、官网 Autoware.Auto (autowarefoundation.gitlab.io) 二、介绍 Autoware是世界上第一个由Autoware基金会托管的用于自动驾驶汽车的“一体化”开源软件。基于 ROS 2 的 Au…

C语言例:表达式(a=2,3),a+1的值

题目&#xff1a;设int a; 则表达式(a2,3),a1的值 #include<stdio.h> int main(void) {int a0;int b;int c;b (a2,4);c (a2,3),a1;printf("a1%d\n",a1); //a1 3;printf("a2,4的值为&#xff1a;%d\n",b); //a2,4的值为&…

开源模型应用落地-业务优化篇(八)

一、前言 在之前的学习中&#xff0c;我相信您已经学会了一些优化技巧&#xff0c;比如分布式锁、线程池优化、请求排队、服务实例扩容和消息解耦等等。现在&#xff0c;我要给您介绍最后一篇业务优化的内容了。这个优化方法是通过定时统计问题的请求频率&#xff0c;然后将一些…

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——蚁群算法(ACO)

基于python语言&#xff0c;采用经典遗传算法&#xff08;ACO&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果4. 代码片段参考 往期优质资源 经过一年多的创作&#xff0c;目前已经成熟…

Go函数全景:从基础到高阶的深度探索

目录 一、Go函数基础1.1 函数定义和声明基础函数结构返回值类型和命名返回值 1.2 参数传递方式值传递引用传递 二、Go特殊函数类型2.1 变参函数定义和使用变参变参的限制 2.2 匿名函数与Lambda表达式何为匿名函数Lambda表达式的使用场景 2.3 延迟调用函数&#xff08;defer&…

Arcgis新建位置分配求解最佳商店位置

背景 借用Arcgis帮助文档中的说明:在本练习中,您将为连锁零售店选择可以获得最大业务量的商店位置。主要目标是要将商店定位在人口集中地区附近,因为这种区域对商店的需求量较大。设立这一目标的前提是假设人们往往更多光顾附近的商店,而对于距离较远的商店则较少光顾。您…

禁止ie自动跳转edge

因为微软对ie已经彻底停止维护了&#xff0c;对于没有升级系统的用户来说&#xff0c;会自动更新edge然后将ie给禁止使用。下面方法有效的解决windows10下&#xff0c;禁止ie自动跳转edge。 方法一&#xff1a;对于2023年10月份前的更新可用 打开控制面板&#xff0c;点击网络…

STM32使用常见错误合集(正在更新版)

本文章记录一些学习STM32的一些错误问题 一、编译、烧录类问题 1、烧录不成功&#xff0c;Keil提示RDDI-DAP Error【场景&#xff1a;PWM驱动直流电机】 解决方案&#xff1a;将电机断开再进行烧录&#xff0c;断开后就可以美美烧录不报错啦~ 二、Keil使用问题 1、打开一个…

2 .Gen<I>Cam模块介绍

模块组成&#xff1a;GenApi&#xff0c;SFNC&#xff0c;GenTL&#xff0c;GenDC&#xff0c;GenCP。 首先让我来看下 GenTL (Transport Layer) GenApi( sometimes simply called the GenICam Standard) 传统相机应用程序二次开发&#xff0c;是基于相机厂家提供的sdk。使用…

IBM:《2024年消费者调研:无处不在的人工智能彻底变革零售业》

1月17日&#xff0c;IBM商业价值研究院最近发布了第三份两年一度的消费者调研报告。 这项名为《无处不在的人工智能彻底改变零售业&#xff1a;客户不会等待》的报告&#xff0c;对包含中国在内的全球近20000名消费者进行了调研&#xff0c;相关结果反映了消费者对零售体验的普…

Java中 常见的开源树库介绍

阅读本文之前请参阅------Java中 树的基础知识介绍 在 Java 中&#xff0c;有几种流行的开源树库&#xff0c;它们提供了丰富的树算法和高级操作&#xff0c;可以帮助开发者更高效地处理树相关的问题。以下是几种常见的 Java 树库及其特点和区别&#xff1a; JTree 特点…