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

Effective C++ 条款49:了解new-handler的行为

Effective C++ 条款49:了解new-handler的行为


核心思想operator new无法满足内存分配请求时,会调用用户指定的错误处理函数(new-handler)。理解并定制此行为可增强程序在内存压力下的健壮性,通过实现类专属new-handler实现精细控制。

⚠️ 1. new-handler机制解析

基本流程

  • 内存分配失败时,C++会循环调用全局new-handler函数

  • 通过std::set_new_handler设置/获取当前处理器:

    #include <new>
    void outOfMemHandler() {std::cerr << "Memory exhausted!";std::abort();
    }int main() {std::set_new_handler(outOfMemHandler);int* p = new int[10000000000]; // 触发处理器
    }
    

new-handler的责任

  1. 释放备用内存:使后续分配可能成功
  2. 更换处理器:安装更有效的处理策略
  3. 卸载自身:将handler设为nullptr(下次失败直接抛异常)
  4. 抛出异常:抛出std::bad_alloc或其派生类型
  5. 终止程序:调用abort()exit()

🚨 2. 类专属new-handler实现

需求场景

  • 特定类需要独立的内存分配失败策略
  • 不影响全局new-handler行为

实现步骤

  1. 声明静态new_handler成员
  2. 提供静态set_new_handler接口
  3. 重载类专属operator new
  4. 使用RAII管理handler状态

完整实现

class Widget {
public:static std::new_handler set_new_handler(std::new_handler p) noexcept;static void* operator new(std::size_t size);
private:static std::new_handler currentHandler;
};// 初始化静态成员
std::new_handler Widget::currentHandler = nullptr;// 设置处理器并返回旧处理器
std::new_handler Widget::set_new_handler(std::new_handler p) noexcept {std::new_handler old = currentHandler;currentHandler = p;return old;
}// 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&) = delete;void operator=(const NewHandlerHolder&) = delete;
};// 类专属operator new
void* Widget::operator new(std::size_t size) {NewHandlerHolder h(std::set_new_handler(currentHandler)); // 安装专属handlerreturn ::operator new(size); // 调用全局operator new
}

使用示例

void widgetMemHandler() {releaseWidgetCache(); // 释放备用内存throw std::bad_alloc();
}Widget::set_new_handler(widgetMemHandler);
Widget* pw = new Widget; // 使用专属处理器

⚖️ 3. 模板化通用解决方案

CRTP模式实现

template<typename T>
class NewHandlerSupport {
public:static std::new_handler set_new_handler(std::new_handler p) noexcept;static void* operator new(std::size_t size);
private:static std::new_handler currentHandler;
};template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler = nullptr;template<typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(std::new_handler p) noexcept 
{std::new_handler old = currentHandler;currentHandler = p;return old;
}template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) {NewHandlerHolder h(std::set_new_handler(currentHandler));return ::operator new(size);
}

应用示例

class Widget : public NewHandlerSupport<Widget> {// 自动获得类专属operator new
};// 设置专属handler
Widget::set_new_handler(customWidgetHandler);

💡 关键设计原则

  1. 处理器链式管理
    分级处理策略实现:

    void primaryHandler() {if (freeCacheMemory()) return;       // 尝试释放缓存std::set_new_handler(fallbackHandler); // 降级处理器
    }void fallbackHandler() {logMemoryEmergency();                // 记录紧急状态throw std::bad_alloc();              // 最终抛出异常
    }// 初始化
    std::set_new_handler(primaryHandler);
    
  2. nothrow new的局限性

    Widget* p1 = new Widget;          // 失败时抛bad_alloc
    Widget* p2 = new (std::nothrow) Widget; // 失败返回nullptr
    // 注意:nothrow仅保证分配不抛异常,构造函数仍可能抛出
    
  3. 智能指针集成
    结合自定义分配策略:

    auto widgetDeleter = [](Widget* p) { p->~Widget(); ::operator delete(p); 
    };std::unique_ptr<Widget, decltype(widgetDeleter)> sp(static_cast<Widget*>(::operator new(sizeof(Widget))),widgetDeleter);new(sp.get()) Widget; // 原位构造
    

现代C++扩展

// C++17 内存分配失败直接抛出异常类型
class MyAllocException : public std::bad_alloc {
public:explicit MyAllocException(std::string msg) : message(std::move(msg)) {}const char* what() const noexcept override { return message.c_str(); }
private:std::string message;
};void myHandler() {throw MyAllocException("Custom memory error");
}

嵌入式系统应用

void embeddedHandler() {if (emergencyMemoryReserved) {releaseEmergencyPool(); // 释放预留内存return;}// 硬件级复位HW_TriggerSoftReset();
}

总结
new-handler机制是C++内存管理的安全网,通过定制处理器可实现从简单终止到复杂恢复策略。类专属new-handler允许不同类拥有独立的内存分配失败处理逻辑,结合RAII和模板技术可构建高效、安全的内存管理体系。在资源受限系统中,合理使用new-handler是确保程序健壮性的关键防线。

http://www.xdnf.cn/news/1324459.html

相关文章:

  • 力扣 hot100 Day77
  • 单片机驱动LCD显示模块LM6029BCW
  • 机器翻译论文阅读方法:顶会(ACL、EMNLP)论文解析技巧
  • STM32学习笔记14-I2C硬件控制
  • 大数据计算引擎(四)—— Impala
  • Fluss:颠覆Kafka的面向分析的实时流存储
  • GPT-5之后:当大模型更新不再是唯一焦点
  • 深度学习必然用到的概率知识
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • 敏感数据加密平台设计实战:如何为你的系统打造安全“保险柜”
  • 遥感机器学习入门实战教程 | Sklearn 案例②:PCA + k-NN 分类与评估
  • Day8--滑动窗口与双指针--1004. 最大连续1的个数 III,1658. 将 x 减到 0 的最小操作数,3641. 最长半重复子数组
  • 具身智能2硬件架构(人形机器人)摘自Openloong社区
  • Next.js 中的 SEO:搜索引擎优化最佳实践
  • flutter项目适配鸿蒙
  • JMeter与大模型融合应用之构建AI智能体:评审性能测试脚本
  • 【Jenkins】03 - 自动构建和docker构建
  • MCP协议演进:从SSE到Streamable HTTP的技术革命
  • 宁波市第八届网络安全大赛初赛(REVERSE-Writeup)
  • FPGA-Vivado2017.4-建立AXI4用于单片机与FPGA之间数据互通
  • OpenTelemetry、Jaeger 与 Zipkin:分布式链路追踪方案对比与实践
  • vscode wsl解决需要用别的用户调试的问题
  • VSCode REST Client 使用总结
  • Linux下的软件编程——IPC机制
  • Linx--MySQL--安装笔记详细步骤!
  • k8sday10服务发现(1/2)
  • 数据泵实施VPS海外:跨国数据同步的完整解决方案
  • 45 C++ STL模板库14-容器6-容器适配器-优先队列(priority_queue)
  • 系统架构评估方法全景解析
  • 【Java基础常见辨析】重载与重写,深拷贝与浅拷贝,抽象类与普通类