尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Item49--了解 new-handler 的行为

Item49--了解 new-handler 的行为
📅 发布时间:2026/6/19 18:12:12

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 的最优雅方式。

相关新闻

  • 2025年年终加气砖厂家综合实力排行榜:全国优质供应商对比评测与选购指南 - 品牌推荐
  • LangFlow团队版即将推出?商业授权模式猜想
  • 数字时代的守护者:“缺人+高薪”网络安全行业热招!

最新新闻

  • 告别GUI开发噩梦:用Dear ImGui在30分钟内为C++项目添加专业界面
  • 这些工具助你轻松下载抖音别人的作品,省时省力 - 工具软件使用方法推荐
  • 钻石回收避坑干货2026 天津,实地探店多家商家,禹竞名奢汇资质正规结算快 - 名奢变现站
  • 如何快速掌握B站工具箱:面向新手的完整免费下载指南
  • Upgrade Win11 subsystem Ubuntu22.04 to ubuntu24.04
  • 2026合肥理工学校职教高考班招生详情|中考200-450分升学通道 - cc江江

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号