跳到主要内容
版本:Next

delete

delete 是 C++98/03 中用于释放由 new 分配对象的运算符。它的职责不只是“还内存”,还包括调用析构函数,确保对象在销毁前完成资源清理。

对于动态数组,必须使用 delete[]。这两种释放方式不能混用。

基本语法

delete p; // 释放单个对象
delete[] arr; // 释放对象数组

规则:

  1. new T 对应 delete
  2. new T[n] 对应 delete[]
  3. 释放后建议把指针置为 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 的关系

deletefree 不能混用:

  1. new / new[]delete / delete[]
  2. malloc / calloc / reallocfree

混用会导致未定义行为。

实战建议

  1. 让每个 new 都有清晰、唯一的释放点。
  2. 释放后立刻置空,减少野指针风险。
  3. 多态基类析构函数设为 virtual
  4. 在 C++98/03 项目中可优先使用 RAII 对象管理资源,减少手写 delete

小结

delete 的关键不是“会写语法”,而是“严格匹配来源并保证生命周期正确结束”。只要坚持配对原则(newdeletenew[]delete[]),并避免重复释放和悬空访问,就能规避绝大多数动态内存错误。