delete 表达式
销毁先前由 new 表达式 分配的对象并释放获取的内存区域。
目录 |
[编辑] 语法
:: (可选) delete 表达式 |
(1) | ||||||||
:: (可选) delete[] 表达式 |
(2) | ||||||||
表达式 | - | 以下之一
|
[编辑] 解释
给定从 表达式 评估出的指针(在可能的转换之后)为 ptr。
delete 表达式的结果总是 void 类型。
如果在删除时,被删除的对象具有不完整的类类型,并且完整类具有非平凡析构函数或解除分配函数,则行为是未定义的(C++26 之前)则程序格式错误(C++26 起)。
如果 ptr 不是空指针且解除分配函数不是销毁性删除(C++20 起),则 delete 表达式会为被销毁的对象或数组的每个元素(从数组的最后一个元素到第一个元素)调用析构函数(如果有)。析构函数必须从 delete 表达式出现的位置可访问。
之后,无论析构函数是否抛出异常,delete 表达式都会调用解除分配函数:operator delete(第一种形式)或 operator delete[](第二种形式),除非匹配的 new 表达式与另一个 new 表达式结合使用(C++14 起)。
解除分配函数的名称在 ptr 所指向对象的动态类型的范围内进行查找,这意味着如果存在类特定的解除分配函数,它们会在全局解除分配函数之前被找到。如果 delete 表达式中存在 ::
,则此查找仅检查全局命名空间。在任何情况下,除了常用解除分配函数之外的任何声明都将被丢弃。
如果找到任何解除分配函数,则按照以下方式选择要调用的函数(有关这些函数及其效果的更详细描述,请参阅解除分配函数)
|
(C++20 起) |
|
(C++17 起) |
- 如果找到的解除分配函数是类特定的,则无大小感知的类特定解除分配函数(不带 std::size_t 类型的参数)优先于大小感知的类特定解除分配函数(带 std::size_t 类型的参数)。
|
(C++14 起) |
选择的解除分配函数必须从 delete 表达式出现的位置可访问,除非解除分配函数是在动态类型的虚析构函数的定义点选择的。
要回收的存储块的指针作为第一个参数传递给上述过程选择的解除分配函数。块的大小作为可选的 std::size_t 参数传递。对齐要求作为可选的 std::align_val_t 参数传递。(C++17 起)
如果 ptr 是空指针值,则不调用析构函数,解除分配函数可能被调用也可能不被调用(未指定),但默认的解除分配函数保证在传递空指针时不做任何事情。
如果 ptr 是指向使用 new 分配的对象的基类子对象的指针,则基类的析构函数必须是虚函数,否则行为是未定义的。
[编辑] 注意
不能删除 void 指针,因为它不是对象类型指针。
由于关键字 delete 后面的方括号对始终被解释为 delete 表达式的数组形式,因此 delete 后立即带有空捕获列表的lambda 表达式必须用括号括起来。 // delete []{ return new int; }(); // parse error delete ([]{ return new int; })(); // OK |
(C++11 起) |
[编辑] 关键字
[编辑] 缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 发布时的行为 | 正确的行为 |
---|---|---|---|
CWG 288 | C++98 | 对于第一种形式,操作数的静态类型 与其动态类型进行比较 |
比较要删除的对象的静态类型 与其动态类型 |
CWG 353 | C++98 | 如果析构函数抛出异常,是否调用解除分配函数 未指定 |
总是调用 |
CWG 599 | C++98 | 第一种形式可以接受任何类型的空指针, 包括函数指针 |
除了对象类型指针, 所有其他指针类型都被拒绝 |
CWG 1642 | C++98 | 表达式 可以是指针左值 | 不允许 |
CWG 2474 | C++98 | 删除指向相似但 不同类型对象的指针会导致未定义行为 |
已明确定义 |
CWG 2624 | C++98 | 从非分配性 operator new[] 获取的指针可以传递给 delete[] |
已禁止 |
CWG 2758 | C++98 | 不清楚解除分配函数和析构函数的访问控制是如何完成的 解除分配函数和析构函数的访问控制 |
已明确 |