new和delete是C++手动管理堆内存的操作符,new分配内存并调用构造函数,delete释放内存并调用析构函数;必须严格配对,否则引发未定义行为;推荐优先使用智能指针和RAII避免内存泄漏。

new 和 delete 是 C++ 中手动管理堆内存的核心操作符,用对了能灵活控制对象生命周期,用错了就容易导致内存泄漏、重复释放或访问已释放内存等严重问题。
new:在堆上分配内存并调用构造函数
使用 new 会在程序运行时从堆(heap)申请内存,并自动调用对应类型的构造函数:
- 分配单个对象:
int* p = new int(42);—— 分配一个 int,初始化为 42 - 分配对象(带构造):
std::string* s = new std::string("hello");—— 调用 string 的构造函数 - 分配数组:
double* arr = new double[10];—— 分配 10 个 double,但不调用构造函数(内置类型无构造);对类类型数组,会逐个调用默认构造函数
注意:new 可能抛出 std::bad_alloc 异常(除非加 nothrow 版本),所以关键逻辑中建议处理异常或用 new(std::nothrow) 检查返回是否为 nullptr。
delete:释放内存并调用析构函数
delete 必须与 new 配对使用,它会先调用对象的析构函数,再把内存归还给系统:
- 释放单个对象:
delete p;—— 对应new T - 释放数组:
delete[] arr;—— 必须用delete[],对应new T[n];用错(比如对数组用delete)是未定义行为,常见于崩溃或数据损坏
释放后指针不会自动变为空,建议手动置 nullptr(如 delete p; p = nullptr;),避免后续误用。
常见错误和如何避免内存泄漏
内存泄漏本质是:分配了内存,却始终没有 delete(或 delete[])它。典型场景包括:
- 函数提前返回没释放:
if (err) return; delete p;→ 应该把delete放在所有出口前,或用 RAII - 异常发生时跳过释放:代码中抛异常,
delete后面的语句没执行 → 推荐用智能指针自动管理 - 指针被覆盖丢失地址:
p = new int(1); p = new int(2);→ 第一块内存再也无法释放 - 多个指针指向同一块内存,多次
delete→ 程序崩溃
最稳妥的解法不是靠人记住配对,而是用 std::unique_ptr 或 std::shared_ptr。例如:auto p = std::make_unique,离开作用域自动释放,彻底规避泄漏风险。
替代方案优先级推荐(现代 C++ 实践)
除非有明确理由(如性能敏感、与 C 接口交互、自定义内存池),否则应避免裸 new/delete:
- 局部对象 → 直接栈上定义(快、安全、自动析构)
- 需要动态生命周期 → 用
std::unique_ptr(独占所有权) - 需要共享所有权 → 用
std::shared_ptr(带引用计数) - 需动态数组 → 用
std::vector或std::unique_ptr - 必须手管内存 → 至少封装到 RAII 类中,确保构造分配、析构释放
裸 new/delete 不是不能用,而是容易错;而智能指针和容器让正确性变成默认行为。