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

Item49--了解 new-handler 的行为

1. new-handler 的基本机制

在标准库中,set_new_handler 是定义在 <new> 头文件中的函数,用于指定当内存分配失败时调用的回调函数。

namespace std {typedef void (*new_handler)();new_handler set_new_handler(new_handler p) throw();
}
  • 参数: p 是你希望在内存分配失败时调用的函数指针。
  • 返回值: 返回在调用之前正在生效的旧 new_handler 指针。

示例代码:

void outOfMemory() {std::cerr << "Unable to satisfy request for memory\n";std::abort();
}int main() {std::set_new_handler(outOfMemory);int* pBigDataArray = new int[1000000000L]; // 如果分配失败,将调用 outOfMemory
}

2. 一个设计良好的 new-handler 应该做什么?

operator new 无法分配内存时,它会反复循环调用 new-handler,直到找到足够的内存。因此,一个设计合理的 new-handler 必须执行以下操作之一:

  1. 让更多内存可用: 比如程序启动时预分配一大块内存,在 handler 中释放它供系统使用。
  2. 安装另一个 new-handler: 如果当前的 handler 无法解决问题,它可能会知道另一个 handler 更有用,从而调用 set_new_handler 替换自己。
  3. 卸载 new-handler:null 传给 set_new_handler。如果没有安装 handler,operator new 在分配失败时会抛出异常。
  4. 抛出异常: 抛出 std::bad_alloc 或其派生类。这个异常不会被 operator new 捕获,而是传播到调用点。
  5. 不返回: 调用 abort()exit() 直接终止程序。

3. 为特定类定制 new-handler

C++ 不直接支持为每个类设置独立的 new-handler,但我们可以通过重载类内部的 operator new 来实现这一行为。

实现思路:

  1. 在类中声明一个静态成员 currentHandler
  2. 重载类的 operator new
  3. operator new 中:
    • 调用全局 set_new_handler 把类的 handler 安装上去,并记录原来的全局 handler。
    • 调用全局 ::operator new 执行实际分配。
    • 无论分配成功与否,都要把原来的全局 handler 还原回来(使用 RAII 确保安全)。

代码实现 (RAII 方式):

class NewHandlerHolder {
public:explicit NewHandlerHolder(std::new_handler nh) : handler(nh) {}~NewHandlerHolder() { std::set_new_handler(handler); }
private:std::new_handler handler;NewHandlerHolder(const NewHandlerHolder&); // 阻止拷贝NewHandlerHolder& operator=(const NewHandlerHolder&);
};class Widget {
public:static std::new_handler set_class_new_handler(std::new_handler p) throw();static void* operator new(std::size_t size) throw(std::bad_alloc);
private:static std::new_handler currentHandler;
};// 静态成员初始化
std::new_handler Widget::currentHandler = 0;
std::new_handler Widget::set_class_new_handler(std::new_handler p) throw() {std::new_handler oldHandler = currentHandler;currentHandler = p;return oldHandler;
}void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {// 1. 安装 Widget 的 handler,并记录旧的全局 handlerNewHandlerHolder h(std::set_new_handler(currentHandler));// 2. 调用全局 operator newreturn ::operator new(size);// 3. h 析构时会自动恢复全局 handler
}

4. 使用 Template 简化重复工作 (Mixin 风格)

为了避免为每个类重复编写上述逻辑,可以创建一个模板基类(常被称为 CRTP:Curiously Recurring Template Pattern)。

template<typename T>
class NewHandlerSupport {
public:static std::new_handler set_class_new_handler(std::new_handler p) throw();static void* operator new(std::size_t size) throw(std::bad_alloc);
private:static std::new_handler currentHandler;
};// 使用方法:
class Widget : public NewHandlerSupport<Widget> {// 此时 Widget 自动拥有了设置专属 new-handler 的能力
};

5. 关于 "nothrow" new

早期的 C++ 分配失败返回 null,现代 C++ 默认抛出异常。为了兼容旧代码,C++ 提供了 nothrow 形式:

Widget* pw1 = new Widget;               // 失败抛出 bad_alloc
Widget* pw2 = new (std::nothrow) Widget; // 失败返回 0 (null)

注意: nothrow 只保证 operator new 本身不抛异常。如果 Widget构造函数内部又用了普通的 new,或者构造函数本身报错,异常依然会产生。因此,nothrow 的意义在现代开发中非常有限。


总结

  1. set_new_handler 允许你指定一个在内存耗尽时被调用的函数。
  2. new-handler 的职责是解决内存问题或终止循环(通过修改 handler、抛异常或退出)。
  3. 类专属 handler 需要通过重载 operator new 并结合 RAII 对象来手动管理切换过程。
  4. CRTP 模板是实现类专属 new-handler 的最优雅方式。
http://www.jsqmd.com/news/122577/

相关文章:

  • 【数据安全新标准】:基于Open-AutoGLM的隐私访问审计6大关键技术
  • 【MWORKS使用技巧86】Sysplorer中如何修改模型浏览器的图标大小
  • Open-AutoGLM数据脱敏规则深度配置(从入门到专家级的4个关键步骤)
  • LangFlow备份与恢复策略制定建议
  • LangFlow团队版即将推出?商业授权模式猜想
  • 2025年年终加气砖厂家综合实力排行榜:全国优质供应商对比评测与选购指南 - 品牌推荐
  • 【Open-AutoGLM敏感数据识别优化】:揭秘企业级数据安全防护的5大核心突破
  • 面试官:Vision-Language 模型中,如何实现跨模态特征对齐?CLIP 与 BLIP 的主要区别?
  • 数字时代的守护者:“缺人+高薪”网络安全行业热招!
  • 【Open-AutoGLM日志管理终极指南】:掌握访问日志留存设置的5大核心技巧
  • 面试官:多模态 Transformer 如何处理不同模态的序列长度差异?
  • 2025年年终北京装修公司推荐:基于真实用户评价与多品牌深度对比的5家高口碑优质之选 - 十大品牌推荐
  • 如何快速入门CTF?从零基础入门到精通,收藏这一篇就够了!
  • 德诺超声波焊接机的优势与选型指南助您精准采购超声波焊接设备
  • 2025年年终加气砖厂家综合实力推荐排行榜:全国品牌对比与工程选购决策指南 - 品牌推荐
  • 【Open-AutoGLM数据安全新突破】:揭秘脱敏后数据恢复控制核心技术
  • LangFlow周边工具链盘点:哪些值得搭配使用?
  • 2025年年终北京别墅装修公司推荐:基于环保标准与长期质保承诺的5家高口碑公司盘点 - 十大品牌推荐
  • 大数据系统测试的数据准备与验证策略
  • Web 安全入门:从 OWASP Top 10 到常见漏洞,从零基础入门到精通,收藏这一篇就够了!_web top10
  • 从崩溃到稳定运行:3步实现Open-AutoGLM更新弹窗无感处理
  • PE-Labeled GUCY2C FcAvi Tag:结直肠癌诊疗的“三合一哨兵“
  • 2025年12月pcb分板机,铣刀分板机,铡刀分板机厂家推荐,高性能与可靠性兼具的优质品牌 - 品牌鉴赏师
  • 【2025-12-19】商业轮回
  • (Open-AutoGLM高阶技巧)多弹窗优先级调度与自动关闭机制设计
  • LangFlow变量作用域管理机制详解
  • 企业级测试管理工具的应用与集成研究
  • Electron 打包与分发
  • zabbix监控MinIO
  • 芯谷科技—D2503A高效降压型DC-DC转换器,助力电源设计新突破 - 详解