Effective C++ 规则49:了解 new-handler 的行为
1、背景
在 C++ 中,new 运算符用于动态分配内存。然而,当内存分配失败时,程序默认会抛出一个 std::bad_alloc 异常。为了更灵活地处理这种情况,C++ 提供了一种机制,允许开发者自定义内存分配失败时的行为。这就是 new-handler 机制的作用。new-handler 是一种回调函数,当 new 操作符无法分配内存时,运行时系统会调用这个回调函数。通过设置自定义的 new-handler,开发者可以在内存分配失败时执行一些特定的操作,例如:
- 释放未使用的内存。
- 记录错误日志。
- 尝试再次分配内存。
- 终止程序或采取其他恢复措施。
new-handler 的设计使程序能够优雅地应对内存分配失败,而不是直接崩溃。
2、如何使用new-handler
C++ 提供了两个与 new-handler 相关的标准函数:
- std::set_new_handler,用于设置全局的 new-handler 函数,定义在头文件 中。
- std::new_handler,是一个函数指针,指向当前的 new-handler,以下是 std::set_new_handler 的函数签名:
#include <new>
std::new_handler std::set_new_handler(std::new_handler new_p) noexcept;
- 参数:new_p 是指向新的 new-handler 函数的指针。
- 返回值:返回之前设置的 new-handler。
- 异常保证:此函数不抛出任何异常。
3、示例代码
以下是一个完整示例,展示如何使用 std::set_new_handler 设置自定义的 new-handler。
#include <iostream>
#include <new> // std::set_new_handler
#include <cstdlib> // std::abort// 自定义 new-handler 函数
void myNewHandler() {std::cerr << "Memory allocation failed. Attempting to recover..." << std::endl;// 可以选择释放资源或记录日志// 示例:直接终止程序std::abort();
}int main() {// 设置全局的 new-handlerstd::set_new_handler(myNewHandler);try {// 故意尝试分配超大内存size_t size = static_cast<size_t>(-1);int* p = new int[size];delete[] p;} catch (const std::bad_alloc& e) {std::cerr << "Caught exception: " << e.what() << std::endl;}return 0;
}
输出结果:Memory allocation failed. Attempting to recover…
因为,当 new 运算符无法分配内存时,运行时调用了自定义的 myNewHandler,打印错误信息并终止程序。如果未设置 new-handler,程序默认会抛出 std::bad_alloc 异常。
有时,我们可能希望为某个特定的类设置专属的 new-handler,而不是全局生效。这可以通过类的静态成员函数实现,代码如下:
#include <iostream>
#include <new>
#include <cstdlib>class Widget {
public:// 设置类专属的 new-handlerstatic void setNewHandler(std::new_handler p) noexcept {currentHandler = p;}// 重载 operator new,使用类专属的 new-handlerstatic void* operator new(size_t size) {std::new_handler oldHandler = std::set_new_handler(currentHandler);void* mem;try {mem = ::operator new(size);} catch (...) {std::set_new_handler(oldHandler); // 恢复旧的 handlerthrow; // 继续抛出异常}std::set_new_handler(oldHandler); // 恢复旧的 handlerreturn mem;}private:static std::new_handler currentHandler;
};// 定义静态成员
std::new_handler Widget::currentHandler = nullptr;// 自定义 new-handler
void customNewHandler() {std::cerr << "Widget allocation failed. Cleaning up..." << std::endl;std::abort();
}int main() {Widget::setNewHandler(customNewHandler);try {// 尝试分配超大内存Widget* w = new Widget[static_cast<size_t>(-1)];delete[] w;} catch (const std::bad_alloc& e) {std::cerr << "Caught exception: " << e.what() << std::endl;}return 0;
}
4、使用new-handler的注意事项
- 确保 new-handler 是无异常的:new-handler 必须是 noexcept 函数。如果 new-handler 抛出异常,标准库会调用 std::terminate。
- 处理恢复逻辑:在 new-handler 中,尝试释放未使用的内存或其他资源,尽量避免直接终止程序。
- 避免递归调用:如果在 new-handler 中尝试再次分配内存,可能导致递归调用 new-handler,最终导致程序崩溃。
- 线程安全性:std::set_new_handler 会影响全局的 new-handler,因此在多线程环境下使用时需要格外小心。
5、总结
new-handler 是 C++ 提供的一种强大的机制,允许开发者在内存分配失败时定制处理逻辑。通过全局或类专属的 new-handler,程序可以优雅地应对内存不足的情况。尽管如此,new-handler 的使用需要谨慎。合理地释放资源、避免递归调用以及处理异常是实现一个可靠 new-handler 的关键。
相关文章:
Effective C++ 规则49:了解 new-handler 的行为
1、背景 在 C 中,new 运算符用于动态分配内存。然而,当内存分配失败时,程序默认会抛出一个 std::bad_alloc 异常。为了更灵活地处理这种情况,C 提供了一种机制,允许开发者自定义内存分配失败时的行为。这就是 new-han…...

头像生成小程序搭建(免费分享)
如下图为小程序页面的基本效果,下面将介绍该小程序的功能 页面template代码如下: <template><view class"avatar-containner"><block v-if"!showCropper"><image class"pageback" src"../../s…...

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)
手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍) 目录 手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)DDPM 原理图Stable Diffusion 原理Stable Diffusion的原理解释Stable Diffusion 和 Diffus…...
MySQL 基础学习(2): INSERT 操作
在这篇文章中,我们将专注于 MySQL 中的 INSERT 操作,深入了解如何高效地向表中插入数据,并探索插入操作中的一些常见错误与解决方案。 一、基础 INSERT 语法 在 MySQL 中,INSERT 操作用于向表中插入新记录,基本语法如…...

openstack 客户端命令行简介
openstack 客户端命令行简介 基本用法常用命令分类**身份认证(Keystone)**常用命令 **计算服务(Nova)**常用命令: **网络服务(Neutron)**常用命令: **块存储服务(Cinder&…...
Oracle查看数据库表空间使用情况
Oracle RAC环境查看表空间使用情况 查询字段释义: NEED_ADDFILE,--是否需增加表空间文件 TABLESPACE_NAME,--表空间名称 TABLESPACE_FILE_COUNT, --表空间当前数据文件数量 NOW_FILEENABLE_BLOCKS,--表空间文件当前数据块数 NOW_FILEENABLE_BYTES_GB,--表空间文件当…...

[护网杯 2018]easy_tornado1
题目 、 依次点击文件查看 /flag.txt flag in /fllllllllllllag /welcome.txt render /hints.txt md5(cookie_secretmd5(filename)) tornado模板注入 报cookie /error?msg{{handler.settings}} cookie_secret: 6647062b-e68d-4406-90d3-06e307fa955c} 使用python脚本…...
关于java实现word(docx、doc)转html的解决方案
最近在研究一些关于文档转换格式的方法,因为需要用在开发的一个项目上,所以投入了一些时间,给大家聊下这块逻辑及解决方案。 一、关于word转换html大致都有哪些方法? (1)使用 Microsoft Word 导出 其实该…...
【8】思科IOS AP升级操作
1.概述 本文主要针对思科AP的升级操作进行记录,思科的AP目前主要分为IOS和COS AP,IOS AP是我们常见的AP3502/AP1602/AP2702等等型号的AP,而COS AP是AP2802/3802等型号的AP。当然这里所指的都是一些室内AP,如AP1572等室外AP也同样适用。本文先对IOS AP的升级操作进行总结,…...

【ROS2】RViz2界面类 VisualizationFrame 详解
1、简述 VisualizationFrame 继承自 QMainWindow 和 WindowManagerInterface; 窗口顶部是常规布局:菜单栏 和 工具栏 窗口中心是 RenderPanel,用来渲染3D画面 周围是dock区域,包括:DisplaysPanel、ViewsPanel、TimePanel、SelectionPanel 和 ToolPropertiesPanel Windo…...

2025年01月24日Github流行趋势
项目名称:shadPS4 项目地址url:https://github.com/shadps4-emu/shadPS4项目语言:C历史star数:15576今日star数:653项目维护者:georgemoralis, psucien, squidbus, raphaelthegreat, DanielSvoboda项目简介…...

Gradle buildSrc模块详解:集中管理构建逻辑的利器
文章目录 buildSrc模块二 buildSrc的使命三 如何使用buildSrc1. 创建目录结构2. 配置buildSrc的构建脚本3. 编写共享逻辑4. 在模块中引用 四 典型使用场景1. 统一依赖版本管理2. 自定义Gradle任务 3. 封装通用插件4. 扩展Gradle API 五 注意事项六 与复合构建(Compo…...
【Airsim 仿真】查找配置文件 settings json 的路径优先级
Airsim 查找配置文件 settings.json 的路径优先级 参考官方文档 Settings - AirSim 文件格式要求 settings.json 文件采用常规的 JSON 格式。在首次启动时,AirSim 会在用户的主文件夹中创建一个没有设置的 settings.json 文件(待测试)。为…...

【FreeRTOS 教程 四】队列创建与发布项目到队列
目录 一、FreeRTOS队列: (1)队列介绍: (2)用户模型说明: (3)阻塞队列: 二、队列管理 API: (1)uxQueueMessagesWaiti…...

STM32项目分享:智能厨房安全检测系统
目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: STM32智能厨房安全检测系统 (资料分…...
2025美赛数学建模MCM/ICM选题建议与分析,思路+模型+代码
2025美赛数学建模MCM/ICM选题建议与分析,思路模型代码,详细更新见文末名片 一、问题A:测试时间:楼梯的恒定磨损(Archaeological Modeling) 适合专业:考古学、历史学、数学、机械工程 难度:中等…...

高并发问题的多维度解决之道
…...

Ubuntu环境 nginx 源码 编译安装
ubuntu 终端 使用 wget 下载源码 sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz解压刚下载的源码压缩包 nginx-1.24.0.tar.gz sudo tar -zxvf nginx-1.24.0.tar.gz 解压完成 产生 nginx-1.24.0 目录 进入该目录 cd ./nginx-1.24.0 目录下有一个可执行文件 con…...

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

编码器和扩散模型
目录 摘要abstract1.自动编码器2.变分编码器(VAE)3.论文阅读3.1 介绍3.2 方法3.3 结论 4.总结参考文献 摘要 本周学习了自动编码器(AE)和变分自动编码器(VAE)的基本原理与实现,分析其在数据降维…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...