0

0

C++内存分配失败如何处理 set_new_handler异常处理机制详解

P粉602998670

P粉602998670

发布时间:2025-07-24 10:57:01

|

859人浏览过

|

来源于php中文网

原创

c++++内存分配失败时可通过set_new_handler自定义处理机制。1. 包含头文件;2. 定义无参返回void的处理函数,如释放内存、记录日志或抛出异常;3. 使用std::set_new_handler设置该函数为全局new handler;4. 在try-catch块中捕获std::bad_alloc异常进行错误处理。多线程下需用互斥锁保障线程安全。此外,还可结合内存池实现更复杂的内存管理策略。

C++内存分配失败如何处理 set_new_handler异常处理机制详解

C++内存分配失败时,通常会抛出std::bad_alloc异常。但实际上,在抛出异常之前,C++提供了一种更灵活的机制:set_new_handler。你可以利用它来自定义内存分配失败时的处理方式,比如尝试释放一些内存,记录日志,或者直接终止程序。

C++内存分配失败如何处理 set_new_handler异常处理机制详解

解决方案:

C++内存分配失败如何处理 set_new_handler异常处理机制详解

处理C++内存分配失败,核心在于使用std::set_new_handler设置一个自定义的处理函数。这个函数会在new操作符分配内存失败时被调用。

立即学习C++免费学习笔记(深入)”;

  1. 包含头文件: 首先,包含必要的头文件 .

    C++内存分配失败如何处理 set_new_handler异常处理机制详解
  2. 定义处理函数: 定义一个函数,该函数不接受任何参数,返回类型为 void。在这个函数里,你可以执行任何你想做的操作,比如释放内存,打印错误信息,或者抛出一个异常。

    Closers Copy
    Closers Copy

    营销专用文案机器人

    下载
    #include 
    #include 
    
    void myNewHandler() {
        std::cerr << "内存分配失败!正在尝试恢复...\n";
        // 尝试释放一些内存...
        // 或者抛出一个异常,终止程序
        throw std::bad_alloc(); // 确保抛出异常,否则会无限循环
    }
  3. 设置新的处理函数: 使用 std::set_new_handler 函数,将你定义的处理函数设置为全局的 new handler。

    int main() {
        std::set_new_handler(myNewHandler);
    
        try {
            // 尝试分配大量内存
            int* bigArray = new int[1024 * 1024 * 1024]; // 1GB
            // 使用 bigArray...
            delete[] bigArray;
        } catch (const std::bad_alloc& e) {
            std::cerr << "捕获到 bad_alloc 异常: " << e.what() << '\n';
            // 进行错误处理
            return 1;
        }
    
        return 0;
    }
  4. 异常处理: 务必使用 try-catch 块来捕获 std::bad_alloc 异常,并进行适当的错误处理。如果在 myNewHandler 中抛出了异常,那么这个异常会被 catch 块捕获。

为什么需要自定义new handler?仅仅抛出异常不够吗?

仅仅依靠std::bad_alloc异常有时候不够灵活。假设你的程序在嵌入式环境中运行,内存非常有限,抛出异常可能不是最佳选择。你可以通过自定义new handler尝试释放一些不重要的内存,然后重试分配。或者,你可以记录详细的错误信息,方便后续调试。甚至,你可以根据不同的内存分配场景设置不同的new handler

如何在多线程环境中使用set_new_handler?

set_new_handler设置的是全局的new handler,这意味着在多线程环境下,所有的线程都会共享同一个new handler。因此,你需要考虑线程安全问题。一种简单的方法是使用互斥锁来保护new handler的设置和访问。

#include 
#include 
#include 
#include 

std::mutex newHandlerMutex;

void myNewHandler() {
    std::cerr << "Thread ID: " << std::this_thread::get_id() << " 内存分配失败!\n";
    // 线程安全地释放内存或执行其他操作
    throw std::bad_alloc();
}

void threadFunction() {
    try {
        int* bigArray = new int[512 * 1024 * 1024]; // 512MB
        delete[] bigArray;
    } catch (const std::bad_alloc& e) {
        std::cerr << "Thread ID: " << std::this_thread::get_id() << " 捕获到 bad_alloc 异常\n";
    }
}

int main() {
    std::lock_guard lock(newHandlerMutex); // 确保只有一个线程设置new handler
    std::set_new_handler(myNewHandler);

    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}

除了释放内存和记录日志,new handler还能做什么?

除了释放内存和记录日志,new handler 还可以做一些更高级的事情。例如,你可以实现一个内存池,当内存分配失败时,从内存池中分配一块内存。或者,你可以根据当前的系统负载,动态调整内存分配策略。甚至,你可以实现一个自定义的内存管理器,完全控制内存的分配和释放。

#include 
#include 
#include 

// 简单的内存池示例
class MemoryPool {
public:
    MemoryPool(size_t blockSize, size_t poolSize) : blockSize_(blockSize), poolSize_(poolSize), allocated_(0) {
        pool_.resize(poolSize * blockSize);
        freeBlocks_.resize(poolSize);
        for (size_t i = 0; i < poolSize; ++i) {
            freeBlocks_[i] = &pool_[i * blockSize];
        }
    }

    void* allocate() {
        if (freeBlocks_.empty()) {
            return nullptr;
        }
        void* block = freeBlocks_.back();
        freeBlocks_.pop_back();
        allocated_++;
        return block;
    }

    void deallocate(void* block) {
        freeBlocks_.push_back(static_cast(block));
        allocated_--;
    }

    size_t getAllocated() const { return allocated_; }
    size_t getBlockSize() const { return blockSize_; }
    size_t getPoolSize() const { return poolSize_; }

private:
    size_t blockSize_;
    size_t poolSize_;
    size_t allocated_;
    std::vector pool_;
    std::vector freeBlocks_;
};

MemoryPool* g_memoryPool = nullptr;

void myNewHandler() {
    std::cerr << "内存分配失败!尝试从内存池分配...\n";
    if (g_memoryPool) {
        void* block = g_memoryPool->allocate();
        if (block) {
            // 找到可用的内存块,但不能直接返回。需要抛出异常,然后被catch,重新分配
            throw std::bad_alloc(); // 抛出异常,让new操作符再次尝试分配
        } else {
            std::cerr << "内存池也耗尽了!\n";
            throw std::bad_alloc();
        }
    } else {
        std::cerr << "内存池未初始化!\n";
        throw std::bad_alloc();
    }
}

int main() {
    g_memoryPool = new MemoryPool(1024, 100); // 100个1KB的块
    std::set_new_handler(myNewHandler);

    try {
        // 尝试分配超过内存池大小的内存
        std::vector allocatedBlocks;
        for (int i = 0; i < 150; ++i) {
            void* block = new char[1024]; // 每次分配1KB
            allocatedBlocks.push_back(block);
        }

        // 释放分配的内存
        for (void* block : allocatedBlocks) {
            delete[] static_cast(block);
        }

    } catch (const std::bad_alloc& e) {
        std::cerr << "捕获到 bad_alloc 异常: " << e.what() << '\n';
        std::cerr << "已分配的内存块数量: " << g_memoryPool->getAllocated() << '\n';
        delete g_memoryPool;
        return 1;
    }

    delete g_memoryPool;
    return 0;
}

这个例子展示了如何使用new handler从一个简单的内存池中分配内存。请注意,这个例子只是一个简单的演示,实际的内存池实现会更复杂,需要考虑线程安全,内存碎片等问题。

相关专题

更多
javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

173

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

92

2025.11.27

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

472

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

111

2025.12.24

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

65

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

45

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

40

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

41

2025.12.31

出现404解决方法大全
出现404解决方法大全

本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。

232

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号