命名空间
变体
操作

删除表达式

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 

销毁之前由 new-表达式 分配的 对象,并释放获得的内存区域。

内容

[编辑] 语法

::(可选) delete   表达式 (1)
::(可选) delete[] 表达式 (2)
表达式 - 以下之一
1) 销毁由 new-表达式 创建的一个非数组对象。
2) 销毁由 new[]-表达式 创建的数组。

[编辑] 解释

给定从 表达式(在可能的转换后)计算出的指针作为 ptr

1) ptr 必须是以下之一
  • 空指针,
  • 指向由 new-表达式 创建的非数组对象的指针,或者
  • 指向由 new-表达式 创建的非数组对象的基子对象的指针。
ptr 的指向类型必须与对象的类型(或基子对象的类型)类似。如果 ptr 是其他任何东西,包括如果它是由 new-表达式 的数组形式获得的指针,则行为是 未定义 的。
2) ptr 必须是空指针或指针,其值先前由 new-表达式 的数组形式获得,其 分配函数 不是非分配形式(即重载 (10))。
ptr 的指向类型必须与数组对象的元素类型类似。如果 ptr 是其他任何东西,包括如果它是由 new-表达式 的非数组形式获得的指针,则行为是 未定义 的。

delete-表达式的结果始终是 void 类型。

如果在删除时,要删除的对象的类类型不完整,并且完整类具有非平凡的析构函数或释放函数,则行为未定义(直到 C++26)程序格式不正确(从 C++26 开始).

如果 ptr 不是空指针并且 释放函数 不是销毁删除(从 C++20 开始),delete 表达式将调用 析构函数(如果有)用于要销毁的对象,或用于要销毁的数组的每个元素(从数组的最后一个元素到第一个元素)。析构函数必须从 delete 表达式出现的点 可访问

在那之后,无论任何析构函数是否抛出异常,delete 表达式都将调用 释放函数:要么是 operator delete(第一个版本)要么是 operator delete[](第二个版本),除非匹配的 new 表达式与另一个 new 表达式结合(从 C++14 开始).

释放函数的名称在 ptr 指向的对象的动态类型的范围内被 查找,这意味着类特定的释放函数(如果有)在全局函数之前被找到。如果 delete 表达式中存在 ::,则此查找只会检查全局命名空间。在任何情况下,除通常的释放函数以外的任何声明都将被丢弃。

如果找到任何释放函数,将按如下方式选择要调用的函数(有关这些函数及其效果的更详细说明,请参阅 释放函数)。

  • 如果至少一个释放函数是销毁删除,所有非销毁删除将被忽略。
(从 C++20 开始)
  • 如果类型的对齐要求超过 __STDCPP_DEFAULT_NEW_ALIGNMENT__,则优先使用支持对齐的释放函数(其参数类型为 std::align_val_t)。对于其他类型,优先使用不支持对齐的释放函数(其参数类型不为 std::align_val_t)。
  • 如果找到多个首选函数,则在下一步中只考虑首选函数。
  • 如果找不到首选函数,则在下一步中考虑非首选函数。
  • 如果只有一个函数剩下,则选择该函数。
(从 C++17 开始)
  • 如果找到的释放函数是类特定的,则无大小感知的类特定释放函数(其参数类型不为 std::size_t)优先于有大小感知的类特定释放函数(其参数类型为 std::size_t)。
  • 否则,查找将到达全局范围,并且
  • 如果类型是完整的,并且,仅对于数组形式,操作数是指向具有非平凡析构函数的类类型或其(可能是多维的)数组的指针,则选择全局大小感知全局函数(其参数类型为 std::size_t)。
  • 否则,全局大小感知释放函数(其参数类型为 std::size_t)或全局无大小感知释放函数(其参数类型不为 std::size_t)是哪个被选择,是未指定的。
(从 C++14 开始)

所选的释放函数必须从 delete 表达式出现的点 可访问,除非释放函数是在 动态类型虚析构函数 定义处选择的。

指向要回收的存储块的指针作为第一个参数传递给通过上述过程选择的 释放函数。块的大小作为可选的 std::size_t 参数传递。 对齐要求作为可选的 std::align_val_t 参数传递。(从 C++17 开始)

如果 ptr 是一个空指针值,则不会调用任何析构函数,并且可能调用也可能不调用释放函数(这是未指定的),但默认的释放函数在传递空指针时保证不执行任何操作。

如果 ptr 是指向用 new 分配的对象的基类子对象的指针,则基类的析构函数必须是 虚的,否则行为未定义。

[edit] 说明

指向 void 的指针不能被删除,因为它不是指向对象类型的指针。

因为在关键字 delete 之后的一对括号总是被解释为 delete 表达式的数组形式,所以 lambda 表达式delete 之后带有空捕获列表,必须用括号括起来。

// delete []{ return new int; }(); // parse error
delete ([]{ return new int; })();  // OK
(从 C++11 开始)

[edit] 关键字

delete

[edit] 缺陷报告

以下行为更改的缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
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 不清楚释放函数和析构函数是如何进行访问控制的
变得清晰

[edit] 另请参阅