Effective C++ 规则51:编写 new 和 delete 时需固守常规

1、背景

在 C++ 中,如果你需要为类自定义 new 和 delete,必须遵循一些约定和规则,以确保内存管理的一致性、可维护性和安全性。当我们使用 new 和 delete 操作时,C++ 编译器会:

  • 调用全局或类特定的 operator new 来分配内存。
  • 调用构造函数(new)或析构函数(delete)。
  • 如果需要,调用全局或类特定的 operator delete 来释放内存。
    通常,类的内存管理行为依赖于全局版本的 operator new 和 operator delete,但在某些场景下,你可能需要为类定义自定义的版本。

2、自定义new和delete的基本规则

2.1、成对出现

如果为类定义了自定义的 operator new,则必须同时定义对应的 operator delete。

#include <iostream>
#include <cstdlib>class Widget {
public:static void* operator new(size_t size) {std::cout << "Custom operator new: Allocating " << size << " bytes" << std::endl;return std::malloc(size);}static void operator delete(void* ptr) noexcept {std::cout << "Custom operator delete: Freeing memory" << std::endl;std::free(ptr);}
};int main() {/*下面这句会执行两步:1、调用 operator new(size_t size) 为对象分配内存,在执行这一步时,会将sizeof(Widget)作为参数2、调用对象的构造函数在分配的内存上初始化对象。*/Widget* w = new Widget;delete w;/*Custom operator new: Allocating 1 bytesCustom operator delete: Freeing memory*/return 0;
}

2.2、匹配的内存分配和释放

  • 任何通过 operator new 分配的内存,必须使用对应的 operator delete 释放。
  • 避免跨越模块或库边界使用不同版本的 new 和 delete。

2.3、确保异常安全

自定义 operator new 应确保在分配失败时抛出 std::bad_alloc,而不是返回 nullptr。

#include <new>
#include <iostream>void* operator new(size_t size) {if (size == 0) size = 1; // 确保非零分配void* ptr = std::malloc(size);if (!ptr) throw std::bad_alloc(); // 分配失败时抛出异常return ptr;
}void operator delete(void* ptr) noexcept {std::free(ptr);
}

2.4、定义 placement new 和 delete

C++ 提供了 placement new,允许你在已分配的内存上构造对象。如果你需要自定义 operator new,也应该定义对应的 placement operator delete。

#include <iostream>class Widget {
public:static void* operator new(size_t size, void* location) {std::cout << "Placement new called" << std::endl;return location;}static void operator delete(void* ptr, void* location) {std::cout << "Placement delete called" << std::endl;// 不释放内存,因为是 placement new}
};int main() {char buffer[sizeof(Widget)];/*下面这句会执行两步:1、调用 operator new(size_t size, void* location),在执行这一步时,会将sizeof(Widget)作为第一个参数,buffer作为第2个参数2、调用对象的构造函数在分配的内存上初始化对象。*/Widget* w = new (buffer) Widget;w->~Widget(); // 显式调用析构函数,输出Placement new calledreturn 0;
}

3、特殊场景

  • 定制小对象分配器,对于需要频繁分配和释放的小对象,可以实现更高效的内存池,这样做可以优化的原因是,提前做好了分配内存的这一步,在获取到内存后,只需要再调用构造函数就可以了。
#include <iostream>
#include <vector>class SmallObjectAllocator {
private:std::vector<void*> freeList;size_t objectSize;public:SmallObjectAllocator(size_t objSize) : objectSize(objSize) {}void* allocate() {if (freeList.empty()) {return std::malloc(objectSize);} else {void* ptr = freeList.back();freeList.pop_back();return ptr;}}void deallocate(void* ptr) {freeList.push_back(ptr);}
};class Widget {
public:static SmallObjectAllocator allocator;static void* operator new(size_t size) {return allocator.allocate();}static void operator delete(void* ptr) {allocator.deallocate(ptr);}
};SmallObjectAllocator Widget::allocator(sizeof(Widget));int main() {Widget* w1 = new Widget;Widget* w2 = new Widget;delete w1;delete w2;return 0;
}
  • 优点,减少小对象分配的开销,提升内存分配性能。

3、总结

在编写 operator new 和 operator delete 时,应遵循以下关键点:

  • 成对定义 new 和 delete,包括 placement 版本。
  • 确保异常安全,分配失败时抛出 std::bad_alloc。
  • 遵循匹配的内存分配和释放规则,避免跨模块不一致。
  • 在需要优化性能时,可实现自定义的内存池或分配器。

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

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

相关文章

2013年蓝桥杯第四届CC++大学B组真题及代码

目录 1A&#xff1a;高斯日记&#xff08;日期计算&#xff09; 2B&#xff1a;马虎的算式&#xff08;暴力模拟&#xff09; 3C&#xff1a;第39级台阶&#xff08;dfs或dp&#xff09; 4D&#xff1a;黄金连分数&#xff08;递推大数运算&#xff09; 5E&#xff1a;前缀…

【数据分享】1929-2024年全球站点的逐月平均能见度(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff01;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2024年全球气象站点…

【动态规划】--- 斐波那契数模型

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 算法Journey &#x1f3e0; 第N个泰波那契数模型 &#x1f4cc; 题目解析 第N个泰波那契数 题目要求的是泰波那契数&#xff0c;并非斐波那契数。 &…

单片机-STM32 WIFI模块--ESP8266 (十二)

1.WIFI模块--ESP8266 名字由来&#xff1a; Wi-Fi这个术语被人们普遍误以为是指无线保真&#xff08;Wireless Fidelity&#xff09;&#xff0c;并且即便是Wi-Fi联盟本身也经常在新闻稿和文件中使用“Wireless Fidelity”这个词&#xff0c;Wi-Fi还出现在ITAA的一个论文中。…

计算机的错误计算(二百二十二)

摘要 利用大模型化简计算 实验表明&#xff0c;虽然结果正确&#xff0c;但是&#xff0c;大模型既绕了弯路&#xff0c;又有数值计算错误。 与前面相同&#xff0c;再利用同一个算式看看另外一个大模型的化简与计算能力。 例1. 化简计算摘要中算式。 下面是与一个大模型的…

ansible自动化运维实战--软件包管理模块、服务模块、文件模块和收集模块setup(4)

文章目录 一、软件包管理模块1.1、功能1.2、常用参数1.3、示例 二、服务模块2.1、功能2.2、服务模块常用参数2.3、示例 三、文件与目录模块3.1、file功能3.2、常用参数3.3、示例 四、收集模块-setup4.1、setup功能4.2、示例 一、软件包管理模块 1.1、功能 Ansible 提供了多种…

高速光模块中的并行光学和WDM波分光学技术

随着AI大模型训练和推理对计算能力的需求呈指数级增长&#xff0c;AI数据中心的网络带宽需求大幅提升&#xff0c;推动了高速光模块的发展。光模块作为数据中心和高性能计算系统中的关键器件&#xff0c;主要用于提供高速和大容量的数据传输服务。 光模块提升带宽的方法有两种…

Linux命令行配置网络代理

在Linux命令行中&#xff0c;你可以使用以下方法设置网络代理服务器。 本文演示代理地址为&#xff1a;http://192.168.1.30:7890 请根据实际代理地址进行替换 临时代理 使用环境变量的方法&#xff1a; 打开终端&#xff0c;并输入以下命令&#xff1a; export http_proxyhtt…

SpringBoot3+Vue3开发学生选课管理系统

功能介绍 分三个角色登录&#xff1a;学生登录&#xff0c;老师登录&#xff0c;教务管理员登录&#xff0c;不同用户功能不同&#xff01; 1.学生用户功能 选课记录&#xff0c;查看选课记录&#xff0c;退选。选课管理&#xff0c;进行选课。通知管理&#xff0c;查看通知消…

牛客周赛 Round 78 A-C

A.时间表查询&#xff01; 链接&#xff1a;https://ac.nowcoder.com/acm/contest/100671/A 来源&#xff1a;牛客网 题目描述 今天是2025年1月25日&#xff0c;今年的六场牛客寒假算法基础集训营中&#xff0c;前两场比赛已经依次于 20250121、20250123 举行&#xff1b;而…

Android - 通过Logcat Manager简单获取Android手机的Log

由于工作需要&#xff0c;经常需要获取Android手机的Log。 平常都是通过adb命令来获取&#xff0c;每次都要写命令。 偶然的一个机会&#xff0c;我从外网发现了一个工具 Logcat Manager&#xff0c;只需要通过简单的双击即可获取Android的Log&#xff0c;这里也分享一下。 目…

苍穹外卖-day10

苍穹外卖-day10 Spring Task Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 cron表达式 cron表达式其实就是一个字符串&#xff0c;通过cron表达式可以定义任务触发的时间 **构成规则&#xff1a;**分为6或7个域&…

一文详解Filter类源码和应用

背景 在日常开发中&#xff0c;经常会有需要统一对请求做一些处理&#xff0c;常见的比如记录日志、权限安全控制、响应处理等。此时&#xff0c;ServletApi中的Filter类&#xff0c;就可以很方便的实现上述效果。 Filter类 是一个接口&#xff0c;属于 Java Servlet API 的一部…

(2)STM32 USB设备开发-USB虚拟串口

例程&#xff1a;STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com 本篇为USB虚拟串口教程&#xff0c;没有知识&#xff0c;全是实操&#xff0c;按照步骤就能获得一个STM32的USB虚拟串口。本例子是在野火F103MINI开发板上验证的&#xff0c;如果代码中出现一些外设的…

K8S中的数据存储之基本存储

基本存储类型 EmptyDir 描述&#xff1a;当 Pod 被调度到节点上时&#xff0c;Kubernetes 会为 Pod 创建一个空目录&#xff0c;所有在该 Pod 中的容器都可以访问这个目录。特点&#xff1a; 生命周期与 Pod 绑定&#xff0c;Pod 删除时&#xff0c;数据也会丢失。适用于临时…

谈谈RTMP|RTSP播放器视频view垂直|水平反转和旋转设计

技术背景 我们在做RTMP|RTSP播放器的时候&#xff0c;有这样的技术诉求&#xff0c;有的摄像头出来的数据是有角度偏差的&#xff0c;比如“装倒了”&#xff0c;或者&#xff0c;图像存在上下或者左右反转&#xff0c;这时候&#xff0c;就需要播放器能做响应的处理&#xff…

自然语言处理——从原理、经典模型到应用

1. 概述 自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是一门借助计算机技术研究人类语言的科学&#xff0c;是人工智能领域的一个分支&#xff0c;旨在让计算机理解、生成和处理人类语言。其核心任务是将非结构化的自然语言转换为机器可以…

【MFC】C++所有控件随窗口大小全自动等比例缩放源码(控件内字体、列宽等未调整) 20250124

MFC界面全自动等比例缩放 1.在初始化里 枚举每个控件记录所有控件rect 2.在OnSize里&#xff0c;根据当前窗口和之前保存的窗口的宽高求比例x、y 3.枚举每个控件&#xff0c;根据比例x、y调整控件上下左右,并移动到新rect struct ControlInfo {CWnd* pControl;CRect original…

SkyWalking介绍

一款开源的系统性能监控工具(APM) 背景 在解决提报的IT性能问题时&#xff0c;由于缺乏系统性能监控运维的工具&#xff0c;导致问题排查非常困难&#xff0c;尤其是偶发的问题&#xff0c;无法进行问题复现还原&#xff0c;需要一套能实时监控线上系统性能的工具平台。 SkyWal…

Pyecharts之图表组合与布局优化

在数据可视化中&#xff0c;我们经常需要将多个图表组合在一起&#xff0c;以展示不同维度的数据或者进行对比分析。同时&#xff0c;合理的布局能够提升图表的可读性和用户体验。Pyecharts 提供了强大的组件和方法&#xff0c;让我们可以轻松实现图表的组合和布局优化。本篇将…