命名空间
变体
操作

delete 表达式

来自 cppreference.cn
< 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 分配的对象的基类子对象的指针,则基类的析构函数必须是虚函数,否则行为是未定义的。

[编辑] 注意

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

由于关键字 delete 后面的方括号对始终被解释为 delete 表达式的数组形式,因此 delete 后立即带有空捕获列表的lambda 表达式必须用括号括起来。

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

[编辑] 关键字

delete

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 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 不清楚解除分配函数和析构函数的访问控制是如何完成的
解除分配函数和析构函数的访问控制
已明确

[编辑] 另请参阅