new(不带std::nothrow)在分配失败时抛出std::bad_alloc异常而非返回nullptr,因此需用try/catch捕获,不能用if(p==nullptr)判空。

new 默认抛出异常,不返回 nullptr
C++ 标准中,new(不带 std::nothrow)在内存分配失败时**不会返回 nullptr,而是抛出 std::bad_alloc 异常**。这是最容易误解的一点——很多从 C 或老式 C++ 习惯过来的人会写 if (p == nullptr) 来判空,结果根本捕获不到失败。
正确做法是用 try/catch 捕获异常:
try {
int* p = new int[1000000000]; // 可能失败
} catch (const std::bad_alloc& e) {
std::cerr <h3>用 std::nothrow 版本才能返回 nullptr</h3><p>如果你确实想用返回值判断(比如嵌入式、禁用异常的环境),必须显式使用 <code>std::nothrow</code> 标签:</p>
-
new (std::nothrow) T返回T*类型,失败时返回nullptr - 不能混用:例如
new (std::nothrow) int[10]是合法的;但new (std::nothrow, align_val_t{16}) int需要 C++17 且对齐参数必须在 nothrow 后 - 注意:即使用了
std::nothrow,构造函数仍可能抛异常(此时内存已分配但对象未构造成功),new会自动调用operator delete释放内存并返回nullptr
示例:
int* p = new (std::nothrow) int[1000000];
if (!p) {
// 分配失败
}
全局 operator new 的行为可被重载,但默认不静默失败
有人以为重载了 operator new 就能控制失败逻辑,但要注意:
- 标准规定:重载的
operator new函数若无法满足请求,**必须抛出std::bad_alloc或等效异常**(或调用std::terminate),不能悄悄返回nullptr - 只有带
std::nothrow_t参数的重载版本(即operator new(size_t, const std::nothrow_t&))才允许返回nullptr - 自定义分配器中若忽略这点,会导致
new (std::nothrow)行为不一致,甚至未定义行为
std::allocator 和容器不暴露分配失败细节
STL 容器(如 std::vector、std::string)内部用 std::allocator,其 allocate() 在失败时也抛 std::bad_alloc。但你通常不会直接调它——问题常出现在:
-
vec.reserve(N)或vec.resize(N)触发大块内存申请时突然崩溃 -
std::string s(N, 'x')构造超长字符串没做异常防护 - 容器方法本身不声明
noexcept(除少数如size()),意味着它们可能抛异常
所以别假设容器操作“很安全”,尤其在资源受限场景下,该包的 try/catch 还是要包。
真正容易被忽略的是:即使你用了 std::nothrow,后续的构造函数失败仍会导致内存被自动释放、指针为 nullptr,但你完全看不到构造过程中的错误信息——这时候得靠自定义分配器或 placement-new + 手动构造来调试。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











