当前位置: 首页 > 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.dtcms.com/a/337878.html

相关文章:

  • JAVA经典面试题:数据库调优
  • 算法题——字符串
  • input 标签的宽度根据内容自动调整
  • 电梯的构造|保养|维修视频全集_电梯安全与故障救援(课程下载)
  • JSX本质是什么
  • AI行业应用深度报告:金融、医疗、教育、制造业落地案例
  • Docker之redis安装
  • linux中的hostpath卷、nfs卷以及静态持久卷的区别
  • 使用websockets中的一些问题和解决方法
  • 数据结构04(Java)-- ( 归并排序及其时间复杂度)
  • gflags框架安装与使用
  • 手机视频怎么提取音频?3步转成MP3,超简单!
  • Vue 中 v-for 的使用及 Vue2 与 Vue3 的区别
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • Navicat 无法登录时找回 SQL 文件的方法
  • Tidio实时聊工具
  • Linux上安装PostgreSQL-源码编译安装备份恢复(超详细)
  • 视觉语言导航(4)——强化学习的三种方法 与 优化算法 2.43.4
  • IP白名单、网段白名单
  • Docker小游戏 | 使用Docker部署文字风格冒险网页小游戏
  • 如何选择一个好的软件成分分析工具?
  • 【计算机视觉与深度学习实战】05计算机视觉与深度学习在蚊子检测中的应用综述与假设
  • 【java中springboot引入geotool】
  • apisix负载均衡测试
  • 负载均衡终极指南:从流量分发到云原生架构的核心解析
  • Spring学习笔记:@Async Spring异步任务的深入学习与使用
  • 基于CentOS 7.6搭建GitLab服务器【玩转华为云】
  • TVS二极管选型指南
  • 构建高效智能语音代理:技术架构、实现细节与API服务推荐
  • 5G + AI + 云:电信技术重塑游戏生态与未来体验