C++中处理内存分配失败有两种核心策略:默认new操作符在失败时抛出std::bad_alloc异常,需用try-catch捕获;而new(std::nothrow)或malloc则返回空指针,需手动检查。选择取决于错误处理哲学和运行环境。

C++中处理内存分配失败,核心策略无非两种:对于默认的
new
std::bad_alloc
new (std::nothrow)
malloc
在C++的世界里,内存分配失败是个不得不面对的现实。想象一下,你的程序正兴高采烈地运行着,突然系统告诉你“对不起,没内存了!”。这时候,我们得有预案。
首先,也是最C++惯用的方式,就是通过异常来处理。当我们直接使用
new
std::bad_alloc
#include <iostream>
#include <vector> // 只是为了模拟一个可能需要大量内存的场景
void allocate_large_memory_with_exception() {
try {
// 尝试分配一个非常大的内存块,例如一个巨大数组
// 在32位系统上,或者内存不足时,这很可能失败
std::vector<int> *big_vec_ptr = new std::vector<int>(1024 * 1024 * 1024 / sizeof(int)); // 1GB
std::cout << "Successfully allocated a large vector (probably not 1GB in reality if it failed)." << std::endl;
// 如果成功,做一些操作
// ...
delete big_vec_ptr; // 别忘了释放
} catch (const std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
// 在这里,我们可以选择:
// 1. 记录日志并尝试恢复(如果可能的话,比如释放其他缓存)
// 2. 优雅地退出程序,例如:exit(EXIT_FAILURE);
// 3. 向上层抛出更具体的自定义异常
std::cerr << "Attempting to gracefully exit or recover..." << std::endl;
// 实际应用中,这里可能包含更复杂的清理逻辑
} catch (const std::exception& e) {
std::cerr << "An unexpected error occurred: " << e.what() << std::endl;
}
}我个人倾向于在大多数现代C++应用中使用
new
try-catch
立即学习“C++免费学习笔记(深入)”;
然而,在某些特定场景下,比如嵌入式系统、对性能极度敏感或不希望使用异常的场合,我们可能更倾向于显式地检查空指针。C++为此提供了
new (std::nothrow)
malloc
NULL
#include <iostream>
#include <new> // for std::nothrow
#include <cstdlib> // for malloc, free
void allocate_memory_with_nothrow_and_malloc() {
// 使用 new (std::nothrow)
int* data = new (std::nothrow) int[1024 * 1024 * 1024]; // 尝试分配1GB的int数组
if (data == nullptr) {
std::cerr << "new (std::nothrow) failed to allocate memory." << std::endl;
// 在这里处理失败,比如:
// 1. 尝试使用更小的内存块
// 2. 记录日志
// 3. 返回错误码
} else {
std::cout << "new (std::nothrow) successfully allocated memory." << std::endl;
delete[] data;
}
std::cout << "---" << std::endl;
// 使用 malloc
char* buffer = (char*)malloc(1024 * 1024 * 1024); // 尝试分配1GB
if (buffer == nullptr) {
std::cerr << "malloc failed to allocate memory." << std::endl;
// 类似地处理失败
} else {
std::cout << "malloc successfully allocated memory." << std::endl;
free(buffer);
}
}在我看来,
new (std::nothrow)
malloc
new
new (std::nothrow)
new
new (std::nothrow)
默认的
new
std::bad_alloc
try-catch
而
new (std::nothrow)
new
nullptr
std::nothrow
new (std::nothrow)
nullptr
那么,该如何选择呢?
这真的取决于你的应用场景和对错误处理的偏好:
使用默认 new
std::bad_alloc
if (ptr == nullptr)
使用 new (std::nothrow)
nullptr
在我看来,除非有非常明确的理由(比如严格的性能要求或不使用异常的编码规范),否则我通常会倾向于使用默认的
new
new (std::nothrow)
除了基本的
try-catch
nullptr
自定义分配器(Custom Allocators) 这是最强大也最灵活的策略之一。你可以通过重载全局的
operator new
operator delete
std::vector
std::map
Allocator
std::bad_alloc
nullptr
std::set_new_handler
new
nothrow
std::bad_alloc
new
new_handler
new_handler
new
std::bad_alloc
std::abort()
std::exit()
new_handler
new_handler
void
new
资源管理(RAII原则)和智能指针 虽然RAII(Resource Acquisition Is Initialization)和智能指针(如
std::unique_ptr
std::shared_ptr
这些高级策略,在我看来,都是为了让我们在面对内存分配这个底层且关键的问题时,能够拥有更精细、更鲁棒的控制力。它们不是简单的替代品,而是对基本异常处理和空指针检查的有力补充,尤其是在构建大型、高性能或高可靠性系统时显得尤为重要。
测试内存分配失败,听起来有点反直觉,因为我们通常希望它不要发生。但为了确保程序在真实世界中遇到内存耗尽时能够优雅地处理,而不是崩溃,我们必须主动去模拟这些场景。这就像是给程序做一次“压力测试”,看看它在极端情况下表现如何。
重载全局 operator new
operator new[]
operator new
operator new[]
operator new
std::bad_alloc
nullptr
operator new(size_t, std::nothrow_t)
#include <new> // For std::bad_alloc
#include <cstdlib> // For malloc, free
#include <iostream>
static int allocation_count = 0;
static int fail_after_n_allocations = -1; // -1 means never fail
void* operator new(std::size_t size) {
if (fail_after_n_allocations != -1 && allocation_count >= fail_after_n_allocations) {
std::cerr << "Simulating memory allocation failure for size " << size << std::endl;
allocation_count = 0; // Reset for next test run if needed
throw std::bad_alloc();
}
allocation_count++;
// 实际的内存分配
void* ptr = malloc(size);
if (ptr == nullptr) {
throw std::bad_alloc(); // If malloc itself fails
}
return ptr;
}
void operator delete(void* ptr) noexcept {
free(ptr);
}
// 重载 new[] 也是类似的
void* operator new[](std::size_t size) {
return operator new(size);
}
void operator delete[](void* ptr) noexcept {
operator delete(ptr);
}
// 在你的测试代码中:
void test_memory_failure_scenario() {
fail_after_n_allocations = 3; // 让第3次分配失败
try {
int* p1 = new int; // 1st
int* p2 = new int; // 2nd
int* p3 = new int; // 3rd, will fail
std::cout << "Should not reach here." << std::endl;
delete p1; delete p2; delete p3; // If somehow succeeded
} catch (const std::bad_alloc& e) {
std::cout << "Caught expected std::bad_alloc: " << e.what() << std::endl;
// 验证程序是否正确处理了异常
}
fail_after_n_allocations = -1; // Reset for other tests
}使用自定义分配器进行测试 如果你的程序已经在使用自定义分配器(例如,为了性能或内存池),那么测试内存分配失败就变得非常简单。你可以在自定义分配器内部添加一个“故障注入”机制。
allocate
nullptr
std::bad_alloc
以上就是C++内存管理基础中内存分配失败异常处理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号