导读:本期聚焦于小伙伴创作的《如何正确处理C++中的内存分配异常 new失败时的异常处理策略》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何正确处理C++中的内存分配异常 new失败时的异常处理策略》有用,将其分享出去将是对创作者最好的鼓励。

在C++程序开发中,动态内存分配是非常常见的操作,我们使用new关键字从堆上申请内存空间。但内存资源是有限的,当系统可用内存不足,或者申请的内存大小超出系统限制时,new操作就会失败。如果开发者没有针对这种失败情况设计对应的处理策略,程序很可能会出现未定义行为甚至直接崩溃,因此掌握new失败时的异常处理方法对写出健壮的C++程序至关重要。

如何正确处理C++中的内存分配异常 new失败时的异常处理策略

new操作的默认异常处理行为

在C++标准定义中,普通的new表达式在分配内存失败时会抛出std::bad_alloc类型的异常。如果程序中没有捕获这个异常,异常会沿着调用栈向上传播,最终如果没有被处理,程序会调用std::terminate终止运行。

我们可以通过下面的代码示例观察默认行为:

#include <iostream>
#include <new>
#include <cstring>

int main() {
    try {
        // 尝试申请一个极大的内存空间,大概率会失败
        long long* huge_mem = new long long[1000000000000];
        std::cout << "内存分配成功" << std::endl;
        delete[] huge_mem;
    } catch (const std::bad_alloc& e) {
        // 捕获new抛出的bad_alloc异常
        std::cout << "捕获到内存分配异常: " << e.what() << std::endl;
    }
    return 0;
}

上述代码中,我们使用try-catch块捕获了std::bad_alloc异常,当new分配失败时,程序不会崩溃,而是会执行catch块中的逻辑,输出异常信息。

使用nothrow版本的new

如果开发者不希望使用异常机制处理new失败的情况,可以使用nothrow版本的new,它的声明在<new>头文件中。nothrow版本的new在分配失败时会返回空指针,而不是抛出异常,开发者可以通过判断返回值是否为nullptr来确定分配是否成功。

对应的使用示例如下:

#include <iostream>
#include <new>

int main() {
    // 使用nothrow版本的new,失败时返回nullptr
    int* mem = new (std::nothrow) int[1000000000];
    if (mem == nullptr) {
        std::cout << "内存分配失败,返回了空指针" << std::endl;
    } else {
        std::cout << "内存分配成功" << std::endl;
        delete[] mem;
    }
    return 0;
}

这种方式适合不希望引入异常处理的场景,但是需要注意,所有使用nothrow new的地方都需要手动判断返回值,否则很容易出现空指针解引用的问题。

自定义new_handler处理全局new失败

当new分配内存失败抛出异常之前,会先调用一个全局的new_handler函数,我们可以通过std::set_new_handler来设置自定义的new_handler。new_handler的函数原型是void(*)(),也就是无参数无返回值的函数指针。

自定义new_handler的典型用途包括:释放一些不必要的缓存来腾出内存、记录内存分配失败的日志、或者直接终止程序。下面是一个自定义new_handler的示例:

#include <iostream>
#include <new>
#include <cstdlib>

// 自定义的new_handler函数
void custom_new_handler() {
    std::cout << "全局new分配内存失败,执行自定义处理逻辑" << std::endl;
    // 这里可以选择释放缓存、记录日志等操作
    // 如果无法处理,可以选择终止程序
    std::abort();
}

int main() {
    // 设置自定义的new_handler
    std::set_new_handler(custom_new_handler);
    try {
        // 尝试分配超大内存
        long long* mem = new long long[1000000000000];
        delete[] mem;
    } catch (const std::bad_alloc& e) {
        std::cout << "捕获到异常: " << e.what() << std::endl;
    }
    return 0;
}

需要注意的是,new_handler函数可以反复被调用,直到内存分配成功或者程序被终止。如果new_handler函数没有终止程序也没有成功腾出内存,可能会导致死循环,因此设计new_handler时需要谨慎。

不同处理策略的适用场景

我们可以根据项目的实际需求选择合适的new失败处理策略:

  • 如果项目已经广泛使用异常机制,那么使用默认的new异常抛出,配合try-catch捕获处理是最规范的做法,符合C++的标准设计理念。
  • 如果项目禁止使用异常,或者是在一些对异常支持不完善的嵌入式环境中开发,那么nothrow版本的new是更合适的选择,只需要每次分配后判断返回值即可。
  • 如果希望对所有new失败的情况做统一的全局处理,比如记录日志、统一释放缓存,那么自定义new_handler是更好的方案,不需要在每个new调用的地方都写重复的处理逻辑。

注意事项

在处理new失败的场景时,有几个常见的误区需要避免:

不要混淆普通的new和new[],两者的失败处理逻辑是一致的,new[]失败同样会抛出std::bad_alloc异常,或者nothrow版本返回nullptr。

另外,不要忘记匹配的内存释放操作,new分配的内存需要用delete释放,new[]分配的内存需要用delete[]释放,否则会导致内存泄漏或者未定义行为。如果使用了自定义的new重载,也需要对应实现自定义的delete重载,保证内存管理的一致性。

最后,即使做了完善的new失败处理,也应该尽量避免频繁申请超大块的内存,合理规划内存使用,从源头减少内存分配失败的概率,才是提升程序稳定性的根本方法。

C++new内存分配异常异常处理修改时间:2026-07-17 08:27:26

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。