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

低层内存管理

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

分配函数

|---------------------------------------------------------------------------------------------|------|-----------|
| 定义于头文件 <new> | | |
| 可替换分配函数 [[nodiscard]] (C++20 起) | | |
| void* operator new ( std::size_t count ); | (1) | |
| void* operator new[]( std::size_t count ); | (2) | |
| void* operator new ( std::size_t count, std::align_val_t al); | (3) | (C++17 起) |
| void* operator new[]( std::size_t count, std::align_val_t al); | (4) | (C++17 起) |
| | | |
| 可替换不抛出分配函数 [[nodiscard]] (C++20 起) | | |
| void* operator new ( std::size_t count, const std::nothrow_t& tag); | (5) | |
| void* operator new[]( std::size_t count, const std::nothrow_t& tag); | (6) | |
| void* operator new ( std::size_t count, std::align_val_t al, const std::nothrow_t&); | (7) | (C++17 起) |
| void* operator new[]( std::size_t count, std::align_val_t al, const std::nothrow_t&); | (8) | (C++17 起) |
| | | |
| 不分配布置分配函数 [[nodiscard]] (C++20 起) | | |
| void* operator new ( std::size_t count, void* ptr ); | (9) | |
| void* operator new[]( std::size_t count, void* ptr ); | (10) | |
| | | |
| 用户定义布置分配函数 | | |
| void* operator new ( std::size_t count, user-defined-args... ); | (11) | |
| void* operator new[]( std::size_t count, user-defined-args... ); | (12) | |
| void* operator new ( std::size_t count, std::align_val_t al, user-defined-args... ); | (13) | (C++17 起) |
| void* operator new[]( std::size_t count, std::align_val_t al, user-defined-args... ); | (14) | (C++17 起) |
| | | |
| 类特定分配函数 | | |
| void* T::operator new ( std::size_t count ); | (15) | |
| void* T::operator new[]( std::size_t count ); | (16) | |
| void* T::operator new ( std::size_t count, std::align_val_t al ); | (17) | (C++17 起) |
| void* T::operator new[]( std::size_t count, std::align_val_t al ); | (18) | (C++17 起) |
| | | |
| 类特定布置分配函数 | | |
| void* T::operator new ( std::size_t count, user-defined-args... ); | (19) | |
| void* T::operator new[]( std::size_t count, user-defined-args... ); | (20) | |
| void* T::operator new ( std::size_t count, std::align_val_t al, user-defined-args... ); | (21) | (C++17 起) |
| void* T::operator new[]( std::size_t count, std::align_val_t al, user-defined-args... ); | (22) | (C++17 起) |

分配请求数量的字节。这些分配函数为 new 表达式所调用,以分配将被初始化的对象所在的内存。亦可用常规函数调用语法调用它们。

  1. 为非数组 new 表达式所调用,以分配为单个对象请求的存储。标准库实现从自由存储分配 count 字节。失败情况下,标准库实现调用 std::get_new_handler 所返回的函数指针,并重复尝试分配,直到 new 处理函数不返回或成为空指针,在该时刻抛出 std::bad_alloc 。要求此函数返回指向拥有请求大小的对象的适当对齐的指针。

  2. 为 new[] 表达式的数组形式所调用,以分配为数组请求的所有存储(包含可能的 new 表达式开销)。标准库实现调用版本 (1)

  3. 为非数组 new 表达式调用,以分配对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的单个对象所要求的存储

  4. 为 new[] 表达式的数组形式调用,以分配对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对象数组要求的所有存储

  5. 为不抛出非数组 new 表达式所调用。标准库实现调用版本 (1) 并在失败时不传播异常而抛出空指针。

  6. 为 new[] 表达式的不抛出数组形式所调用。标准库实现调用版本 (2) 并在失败时不传播异常而抛出空指针。

  7. 在对象对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 时为不抛出非数组 new 表达式所调用。标准库实现调用版本 (3) 并在失败时不传播异常而抛出空指针。

  8. 在数组元素的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 时为 new[] 表达式的不抛出数组形式所调用。标准库实现调用版本 (4) 并在失败时不传播异常而抛出空指针。

  9. 为标准单对象布置 new 表达式所调用,标准库实现不进行任何动作并返回不修改的 ptr

  10. 为标准数组形式布置 new 表达式所调用。标准库实现不进行任何动作并返回不修改的 ptr

  11. 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式所调用。若定义类特定版本 (19) ,则优先于 (11) 调用类特定版本。若用户既不提供 (11) 又不提供 (19) ,则布置 new 表达式为病式。

  12. 若定义,则为拥有匹配签名的自定义数组形式布置 new 表达式所调用。若定义类特定版本 (20) ,则优先于 (12) 调用类特定版本。若用户既不提供 (12) 又不提供 (20) ,则布置 new 表达式为病式。

  13. 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式所调用,若对象的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若定义类特定版本( (15) 或 (17) ),则调用之。若既不提供类特定版本又不提供具对齐布置形式(此形式),则替而查找无对齐布置形式 (11) 。

  14. 若定义,则为拥有匹配签名的自定义数组形式布置 new 表达式所调用,若元素的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若定义类特定版本((16) 或 (18) ),则调用之。若既不提供类特定版本又不提供具对齐布置形式(此形式),则替而查找无对齐布置形式 (12) 。

  15. 若定义,则为通常的单对象 new 表达式所调用,若在分配 T 类型对象。

  16. 若定义,则为通常的数组 new[] 表达式所调用,若在分配 T 类型对象的数组。

  17. 若定义,则为通常的单对象 new 表达式所调用,若在分配 T 类型对象,且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载,但提供了无对齐成员形式 (15) ,则调用无对齐成员重载。

  18. 若定义,通常的数组 new[] 表达式所调用,若在分配 T 类型的对象数组,且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载,但提供了无对齐成员形式 (16) ,则调用无对齐成员重载。

  19. 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式所调用,若在分配 T 类型对象。

  20. 若定义,则为拥有匹配签名的自定义数组形式布置 new 表达式所调用,若在分配 T 类型对象的数组。

  21. 若定义,则为拥有匹配签名的自定义单对象布置 new 表达式所调用,若在分配 T 类型对象,且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载,但提供了无对齐成员形式 (19) ,则调用无对齐成员重载。

  22. 若定义,则为拥有匹配签名的自定义数组形式布置 new 表达式所调用,若在分配 T 类型的对象数组,且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载,但提供了无对齐成员形式 (20) ,则调用无对齐成员重载。

参数

|-------|---|-----------------------|
| count | - | 要分配的字节数 |
| ptr | - | 指向要初始化的对象所在的内存区域的指针 |
| tag | - | 用于选择不抛出重载的消歧义标签 |
| al | - | 使用的对齐。若此非有效对齐值,则行为未定义 |

返回值

1-4) 非空指针,指向拥有至少 size 大小的适当对齐的内存

5-8) 非空指针,指向拥有至少 size 大小的适当对齐的内存,或在失败时为空指针

9-10) ptr

11-22) 若函数在分配失败时不返回则同 (1-4) ,否则同 (5-8)

异常

1-4) 在分配内存失败时抛出 std::bad_alloc 或任何从 std::bad_alloc 派生的异常 (C++11 起)

5-10)

|-----------------------|-----------|
| (无) | (C++11 前) |
| noexcept 规定: noexcept | (C++11 起) |

11-22) 若函数在分配失败时不返回则同 (1-4) ,否则同 (5-8)

全局替换

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

若程序中为任何可替换分配函数提供多于一个替换版本,或若替换定义带 inline 指定符,则行为未定义。若替换定义于异于全局命名空间的命名空间中,或它定义为在全局作用域的 static 函数,则程序为病式。

|-----------------------------------------------------------------------------------------------------------|-----------|
| nothrow 版本的标准库实现 (5-8) 直接调用对应的抛出版本 (1-4) 。抛出的数组版本的标准库实现 (2,4) 直接调用对应的单对象版本 (1,3) 。故而,替换抛出单对象分配函数足以处理所有分配。 | (C++11 起) |

相关推荐
Source.Liu8 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng9 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马12 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng15 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
Jacob程序员17 分钟前
java导出word文件(手绘)
java·开发语言·word
小白学大数据24 分钟前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
VBA633726 分钟前
VBA之Word应用第三章第三节:打开文档,并将文档分配给变量
开发语言
半盏茶香26 分钟前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
小堇不是码农32 分钟前
在VScode中配置C_C++环境
c语言·c++·vscode
Jack黄从零学c++35 分钟前
C++ 的异常处理详解
c++·经验分享