当前位置: 首页 > news >正文

C++标准模板(STL)- 低层内存管理 - 解分配函数 (operator delete, operator delete[])

低层内存管理


new 表达式是创建拥有动态存储期对象或对象数组的仅有方式,即它们拥有不受制于创建所它们在的作用域的生存期。 new 表达式通过调用分配函数获得存储。 delete 表达式销毁最终导出对象或通过 new 表达式创造的数组,然后调用解分配函数。默认分配函数和默认解分配函数,及与之关联的函数、类型及对象声明于头文件 <new> 。

解分配函数

operator delete, 
operator delete[]

定义于头文件 <new>

可替换通常解分配函数

void operator delete  ( void* ptr ) throw();

(1)(C++11 前)

void operator delete  ( void* ptr ) noexcept;

(C++11 起)

void operator delete[]( void* ptr ) throw();

(2)(C++11 前)

void operator delete[]( void* ptr ) noexcept;

(C++11 起)

void operator delete  ( void* ptr, std::align_val_t al ) noexcept;

(3)(C++17 起)

void operator delete[]( void* ptr, std::align_val_t al ) noexcept;

(4)(C++17 起)

void operator delete  ( void* ptr, std::size_t sz ) noexcept;

(5)(C++14 起)

void operator delete[]( void* ptr, std::size_t sz ) noexcept;

(6)(C++14 起)

void operator delete  ( void* ptr, std::size_t sz,
                        std::align_val_t al ) noexcept;

(7)(C++17 起)

void operator delete[]( void* ptr, std::size_t sz,
                        std::align_val_t al ) noexcept;

(8)(C++17 起)

可替换布置解分配函数

void operator delete  ( void* ptr, const std::nothrow_t& tag ) throw();

(9)(C++11 前)

void operator delete  ( void* ptr, const std::nothrow_t& tag ) noexcept;

(C++11 起)

void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw();

(10)(C++11 前)

void operator delete[]( void* ptr, const std::nothrow_t& tag ) noexcept;

(C++11 起)

void operator delete  ( void* ptr, std::align_val_t al,
                        const std::nothrow_t& tag ) noexcept;

(11)(C++17 起)

void operator delete[]( void* ptr, std::align_val_t al,
                        const std::nothrow_t& tag ) noexcept;

(12)(C++17 起)

不分配布置解分配函数

void operator delete  ( void* ptr, void* place ) throw();

(13)(C++11 前)

void operator delete  ( void* ptr, void* place ) noexcept;

(C++11 起)

void operator delete[]( void* ptr, void* place ) throw();

(14)(C++11 前)

void operator delete[]( void* ptr, void* place ) noexcept;

(C++11 起)

用户定义的布置解分配函数

void operator delete  ( void* ptr, args... );

(15)

void operator delete[]( void* ptr, args... );

(16)

类特定通常解分配函数

void T::operator delete  ( void* ptr );

(17)

void T::operator delete[]( void* ptr );

(18)

void T::operator delete  ( void* ptr, std::align_val_t al );

(19)(C++17 起)

void T::operator delete[]( void* ptr, std::align_val_t al );

(20)(C++17 起)

void T::operator delete  ( void* ptr, std::size_t sz );

(21)

void T::operator delete[]( void* ptr, std::size_t sz );

(22)

void T::operator delete  ( void* ptr, std::size_t sz, std::align_val_t al );

(23)(C++17 起)

void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al );

(24)(C++17 起)

类特定布置解分配函数

void T::operator delete  ( void* ptr, args... );

(25)

void T::operator delete[]( void* ptr, args... );

(26)

类特定销毁解分配函数

void T::operator delete(T* ptr, std::destroying_delete_t);

(27)(C++20 起)

void T::operator delete(T* ptr, std::destroying_delete_t,
                        std::align_val_t al);

(28)(C++20 起)

void T::operator delete(T* ptr, std::destroying_delete_t, std::size_t sz);

(29)(C++20 起)

void T::operator delete(T* ptr, std::destroying_delete_t,
                        std::size_t sz, std::align_val_t al);

(30)(C++20 起)

解分配先前由匹配的 operator new 所分配的存储。这些解分配函数为 delete 表达式与 new 表达式所调用,以在析构(或构造失败)拥有动态存储期的对象后解分配内存。它们亦可用常规函数调用语法调用。

1) 为 delete 表达式所调用,以解分配先前为单对象分配的存储。此函数的标准库实现的行为未定义,除非 ptr 是空指针或是先前从 operator new(size_t) 或 operator new(size_t, std::nothrow_t) 的标准库实现获得的指针。

2) 为 delete[] 表达式所调用,以解分配先前为对象数组分配的存储。此函数的标准库实现的行为未定义,除非 ptr 是空指针或是先前从 operator new[](size_t) 或 operator new[](size_t, std::nothrow_t) 的标准库实现获得的指针。

3,4) 同 (1,2) ,除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用

5,6) 若提供用户定义重载,则取代 (1-2) 得到调用,除了在删除不完整类型的对象、非类类型的数组和可平凡析构类类型的数组时,调用 (1-2) 还是 (5-6) 是未指定的。内存分配器可用给定的大小变得更高效。标准库实现等同于 (1-2) 。

7,8) 同 (5-6) ,除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用

9) 若对象的构造函数抛出异常,则为不抛出的单对象 new 表达式所调用。标准库实现表现同 (1)

10) 若任何对象的构造函数抛出异常,则(在执行数组中已成功构造的所有对象的析构函数后)为不抛出的数组 new[] 表达式所调用。标准库实现表现同 (2)

11,12) 同 (9,10) ,除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用

13) 若对象的构造函数抛出异常,则为标准单对象布置 new 表达式所调用。此函数的标准库实现不做任何事。

14) 若任何对象的构造函数抛出异常,则为布置 new 表达式的数组形式(在执行数组中已成功构造的所有对象的析构函数后)所调用。此函数的标准库实现不做任何事。

15) 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式调用,若对象构造函数抛出异常。若定义类特定版本 (25) ,则类特定版本优先于 (9) 调用。若用户既不提供 (25) 又不提供 (15) ,则不调用解分配函数。

16) 若定义,则为拥有匹配签名的布置 new[] 表达式自定义数组形式(在执行数组中已成功构造的所有对象的析构函数后)调用,若任何对象的构造函数抛出异常。若定义类特定版本 (16) ,则类特定版本优先于 (10) 调用。若用户既不提供 (26) 又不提供 (16) ,则不调用解分配函数。

17) 若定义,则为通常单对象 delete 表达式调用,若在解分配一个 T 类型对象。

18) 若定义,则为通常数组 delete[] 表达式调用,若在解分配 T 类型对象的数组。

19,20) 若定义,则优先于 (17,18) 调用,若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__

21) 若定义,且若未定义 (17) ,则为通常单对象 delete 表达式调用,若在解分配一个 T 类型对象。

22) 若定义,且若未定义 (18) ,则为通常数组 delete[] 表达式调用,若在解分配 T 类型对象的数组。

23,24) 若定义,且若未定义 (19,20) ,则优先于无对齐成员调用,若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__.

25) 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式调用,若对象构造函数抛出异常。若不提供此函数,亦不提供匹配的 (15) ,则不调用解分配函数。

26) 若定义,则为拥有匹配签名的自定义布置 new[] 表达式的数组形式(在执行数组中已成功构造的所有对象的析构函数后)调用,若任何对象的构造函数抛出异常。若不提供此函数,亦不提供匹配的 (16) ,则不调用析构函数。

27-30) 若定义,则 delete 表达式在调用 operator delete 前不对 *p 执行析构函数。取而代之地,变为由此用户定义的 operator delete 负责直接调用析构函数,例如用 p->~T(); 。

通常(非布置)解分配函数的具对齐和不具对齐重载之间的重载决议准确细节见 delete 表达式。

(C++17 起)

所有情况下,若 ptr 是空指针,则标准库解分配函数不做任何事。若传递给标准库解分配函数的指针不是从对应的标准库分配函数取得者,则行为未定义。

在标准库解分配函数返回后,所有引用到被解分配存储的任何部分的指针都变为非法。

已因此方式变为非法的指针的任何使用,即使是复制指针值到另一指针变量,都是未定义行为。

(C++14 前)

通过已因此方式变为非法的指针解引用,以及将它传递给解分配函数(双重 delete )是未定义行为。任何其他使用是实现定义的。

(C++14 起)

参数

ptr-指向要解分配的内存块的指针或空指针
sz-传递给匹配的分配函数的 size
place-用作匹配的布置 new 中布置参数的指针
tag-匹配不抛出 operator new 所用标签的重载消歧义标签
al-被分配的对象或数组元素的对齐
args-匹配布置分配函数的任意参数(可包含 std::size_t 与 std::align_val_t )

返回值

(无)

异常

15-30) 容许用户定义的解分配函数抛异常。

(C++11 前)

15-30) 所有解分配函数均为 noexcept(true) ,除非在声明中另外说明。若解分配函数以抛异常终止,则行为未定义,即使以 noexcept(false) 声明它。

(C++11 起)

全局替换

可替换解分配函数 (1-10) 在每个翻译单元隐式声明,即使不包含 <new> 头文件。这些函数是可替换的:定义于程序任何位置、任何头文件的用户提供的拥有相同签名的非成员函数,会为整个程序替换对应的隐式版本。其声明不必可见。

若程序中提供多于一个替换,或若替换声明有 inline 指定符,则行为未定义,若替换声明于异于全局命名空间的命名空间,或若它定义为在全局作用域的 static 非成员函数,则程序为病态。

nothrow 版本 (9,10) 的标准库实现直接调用抛出版本 (1,2) 。具大小解分配函数 (5-8) 的标准库实现直接调用对应的不具大小解分配函数 (1-4) 。不具大小的抛出数组形式 (2,4) 的标准库实现直接调用对应的单对象形式 (1,3) 。

故而,替换抛出的单对象解分配函数 (1,3) 足以处理所有解分配。

(C++11 起)
http://www.lryc.cn/news/420060.html

相关文章:

  • LeetCode 热题 HOT 100 (025/100)【宇宙最简单版】
  • 【mysql 第三篇章】一条 update语句是怎么持久化到磁盘上的?
  • 深入探索大模型:从基础到实践,开启AI之旅
  • 题解:力扣1567 - 返回乘积为正数的最长子数组
  • 009 | 上证50ETF基金数据分析及预测
  • Wakanda: 1靶场复现【附代码】(权限提升)
  • 内核函数调试
  • Spring IOC使用DButil实现对数据库的操作
  • Android14音频进阶调试之命令播放mp3/aac非裸流音频(八十)
  • vue中怎么自定义组件
  • BM1反转链表[栈+头插法]
  • VisionPro二次开发学习笔记10-使用 PMAlign和Fixture固定Blob工具检测孔
  • 学单片机怎么在3-5个月内找到工作?
  • 探索设计模式:观察者模式
  • gradio之持续输入,持续输出(流式)
  • Git 常用命令指南:从入门到精通
  • Camera驱动 汇总表【小驰行动派】
  • SSRS rdlc报表 九 在.net core中使用RDLC报表
  • 力扣(2024.08.10)
  • Django-文件上传
  • [Meachines] [Easy] valentine SSL心脏滴血+SSH-RSA解密+trp00f自动化权限提升+Tmux进程劫持权限提升
  • 利用单张/多张图内参数标定 OpenCV Python
  • The Llama 3 Herd of Models 第7部分视觉实验部分全文
  • 亚信安慧AntDB-T:使用Brin索引提升OLAP查询性能以及节省磁盘空间
  • web渗透测试常用命令
  • Kylin系列(二)使用
  • CI/CD——CI持续集成实验
  • 2.4 大模型数据基础:预训练阶段数据详解 ——《带你自学大语言模型》系列
  • Kali Linux——网络安全的瑞士军刀
  • UML建模-测试用例