delete
delete 是 C++98/03 中用于释放由 new 分配对象的运算符。它的职责不只是“还内存”,还包括调用析构函数,确保对象在销毁前完成资源清理。
对于动态数组,必须使用 delete[]。这两种释放方式不能混用。
基本语法
delete p; // 释放单个对象
delete[] arr; // 释放对象数组
规则:
new T对应delete。new T[n]对应delete[]。- 释放后建议把指针置为
0(C++98/03 无nullptr)。
释放单对象
#include <iostream>
class Demo {
public:
Demo() { std::cout << "Demo ctor\n"; }
~Demo() { std::cout << "Demo dtor\n"; }
};
int main() {
Demo* p = new Demo;
delete p;
p = 0;
return 0;
}
执行 delete p 时会先调用 ~Demo(),再释放对象占用的内存。
释放数组
#include <iostream>
class Item {
public:
Item() { std::cout << "Item ctor\n"; }
~Item() { std::cout << "Item dtor\n"; }
};
int main() {
Item* arr = new Item[3];
delete[] arr;
arr = 0;
return 0;
}
delete[] 会为数组中每个元素调用析构函数。若误用 delete arr,行为未定义,可能导致析构不完整或程序异常。
空指针与 delete
对空指针执行 delete 是安全的,不会产生任何动作:
int* p = 0;
delete p; // 安全,无效果
因此,释放后把指针置空可以降低重复释放风险。
常见陷阱
1) new/delete 不匹配
int* arr = new int[10];
// delete arr; // 错误,应为 delete[] arr
delete[] arr;
2) 重复释放
int* p = new int(5);
delete p;
// delete p; // 错误:重复释放
p = 0;
3) 悬空指针访问
int* p = new int(7);
delete p;
// int x = *p; // 错误:p 已悬空
p = 0;
4) 释放非 new 内存
int x = 10;
int* p = &x;
// delete p; // 错误:p 并非 new 得到
只有通过 new / new[] 得到的指针,才能交给 delete / delete[]。
析构函数与多态删除
通过基类指针删除派生对象时,基类析构函数应声明为虚函数:
#include <iostream>
class Base {
public:
virtual ~Base() { std::cout << "Base dtor\n"; }
};
class Derived : public Base {
public:
~Derived() { std::cout << "Derived dtor\n"; }
};
int main() {
Base* p = new Derived;
delete p;
return 0;
}
如果基类析构不是虚函数,可能只调用基类析构,导致派生部分资源泄漏。
delete 与 free 的关系
delete 和 free 不能混用:
new/new[]配delete/delete[]。malloc/calloc/realloc配free。
混用会导致未定义行为。
实战建议
- 让每个
new都有清晰、唯一的释放点。 - 释放后立刻置空,减少野指针风险。
- 多态基类析构函数设为
virtual。 - 在 C++98/03 项目中可优先使用 RAII 对象管理资源,减少手写
delete。
小结
delete 的关键不是“会写语法”,而是“严格匹配来源并保证生命周期正确结束”。只要坚持配对原则(new 对 delete,new[] 对 delete[]),并避免重复释放和悬空访问,就能规避绝大多数动态内存错误。