operator new, operator new[]
定义于头文件 <new>
|
||||||
可替换分配函数
|
||||||
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 起) | ||||
可替换不抛出分配函数
|
||||||
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 起) | ||||
不分配布置分配函数
|
||||||
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 表达式所调用,以分配将被初始化的对象所在的内存。亦可用常规函数调用语法调用它们。
count
字节。失败情况下,标准库实现调用 std::get_new_handler 所返回的函数指针,并重复尝试分配,直到 new 处理函数不返回或成为空指针,在该时刻抛出 std::bad_alloc 。要求此函数返回指向拥有请求大小的对象的适当对齐的指针。__STDCPP_DEFAULT_NEW_ALIGNMENT__
时为 new[] 表达式的不抛出数组形式所调用。标准库实现调用版本 (4) 并在失败时不传播异常而抛出空指针。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若定义类特定版本( (15) 或 (17) ),则调用之。若既不提供类特定版本又不提供具对齐布置形式(此形式),则替而查找无对齐布置形式 (11) 。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若定义类特定版本((16) 或 (18) ),则调用之。若既不提供类特定版本又不提供具对齐布置形式(此形式),则替而查找无对齐布置形式 (12) 。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若不提供此重载,但提供了无对齐成员形式 (15) ,则调用无对齐成员重载。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若不提供此重载,但提供了无对齐成员形式 (16) ,则调用无对齐成员重载。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若不提供此重载,但提供了无对齐成员形式 (19) ,则调用无对齐成员重载。__STDCPP_DEFAULT_NEW_ALIGNMENT__
。若不提供此重载,但提供了无对齐成员形式 (20) ,则调用无对齐成员重载。参数
count | - | 要分配的字节数 |
ptr | - | 指向要初始化的对象所在的内存区域的指针 |
tag | - | 用于选择不抛出重载的消歧义标签 |
al | - | 使用的对齐。若此非有效对齐值,则行为未定义 |
返回值
size
大小的适当对齐的内存size
大小的适当对齐的内存,或在失败时为空指针ptr
异常
全局替换
版本 (1-4) 在每个翻译单元隐式声明,即使不包含 <new>
头文件。版本 (1-8) 是可替换的:定义于程序任何位置,在任何源文件的用户提供的拥有相同签名的非成员函数,会替换默认版本。其声明不必可见。
若程序中为任何可替换分配函数提供多于一个替换版本,或若替换声明带 inline
说明符,则程序非良构,不要求诊断。若替换定义于异于全局命名空间的命名空间中,或它定义为在全局作用域的 static 函数,则程序为非良构。
nothrow 版本的标准库实现 (5-8) 直接调用对应的抛出版本 (1-4) 。抛出的数组版本的标准库实现 (2,4) 直接调用对应的单对象版本 (1,3) 。故而,替换抛出单对象分配函数足以处理所有分配。 |
(C++11 起) |
#include <cstdio> #include <cstdlib> #include <new> // 最小函数集的替换: void* operator new(std::size_t sz) // 无 inline ,由 [replacement.functions]/3 要求 { std::printf("global op new called, size = %zu\n", sz); if (sz == 0) ++sz; // 避免可能在成功时返回 nullptr 的 std::malloc(0) if (void *ptr = std::malloc(sz)) return ptr; throw std::bad_alloc{}; // 由 [new.delete.single]/3 要求 } void operator delete(void* ptr) noexcept { std::puts("global op delete called"); std::free(ptr); } int main() { int* p1 = new int; delete p1; int* p2 = new int[10]; // C++11 中保证调用替换 delete[] p2; }
可能的输出:
global op new called, size = 4 global op delete called global op new called, size = 40 global op delete called
operator new
与 operator new[]
带额外用户定义参数的重载(“布置形式”,版本 (11-14) )可以照常声明于全局作用域,而且为匹配的 new 表达式的布置形式所调用。
标准库的 operator new 的不分配布置形式 (9-10) 不能被替换,而且只若布置 new 表达式不使用 ::new
语法才能自定义,通过提供类特定的带匹配签名的布置 new (19,20) : void* T::operator new(size_t, void*)
或 void* T::operator new[](size_t, void*)
。
布置形式 |
(C++14 起) |
类特定重载
单对象和数组分配函数都可以定义为类的公开静态成员函数(版本 (15-18) 。若定义,则 new 表达式调用这些函数,以分配此类单个对象或数组的内存,除非 new 表达式使用 ::new
形式,这跳过类作用域查找。关键词 static
对这些函数可选:不管是否使用,分配函数都是静态成员函数。
new 表达式首先在类作用域中查找适当的函数名,然后在全局作用域查找。注意,同每个名称查找规则,就试图分配此类对象的 new 表达式而言,任何声明于类作用域的分配函数隐藏所有全局分配函数。
在分配对齐超出 |
(C++17 起) |
#include <iostream> // 类特定分配函数 struct X { static void* operator new(std::size_t sz) { std::cout << "custom new for size " << sz << '\n'; return ::operator new(sz); } static void* operator new[](std::size_t sz) { std::cout << "custom new[] for size " << sz << '\n'; return ::operator new(sz); } }; int main() { X* p1 = new X; delete p1; X* p2 = new X[10]; delete[] p2; }
可能的输出:
custom new for size 1 custom new[] for size 10
operator new
与 operator new[]
带额外用户定义参数(“布置形式”)的重载,亦可定义为类成员 (19-22) 。在拥有匹配签名的布置 new 表达式查找要调用的对应分配函数时,查找在检验全局作用域前,从类作用域开始,而若提供了类特定的布置 new 则调用它。
在分配对齐超出 |
(C++17 起) |
#include <stdexcept> #include <iostream> struct X { X() { throw std::runtime_error(""); } // 自定义布置 new static void* operator new(std::size_t sz, bool b) { std::cout << "custom placement new called, b = " << b << '\n'; return ::operator new(sz); } // 自定义布置 delete static void operator delete(void* ptr, bool b) { std::cout << "custom placement delete called, b = " << b << '\n'; ::operator delete(ptr); } }; int main() { try { X* p1 = new (true) X; } catch(const std::exception&) { } }
输出:
custom placement new called, b = 1 custom placement delete called, b = 1
若类级别的 operator new
是模板函数,则它必须拥有返回类型 void*
,第一参数类型 std::size_t
,且它必须拥有二个或更多参数。换言之,仅布置形式能是模板。
注解
尽管不分配布置 new (9,10) 不能被替换,亦可在上面描述的类作用域定义拥有相同签名的函数。而且,像是布置 new 但接受非 void 指针类型作为第二参数的全局重载是的受到允许的,故意图确保调用真的布置 new 的代码(例如 std::allocator::construct )必须使用 ::new
并将指针转型到 void*
。
要求下列函数是线程安全的:
对这些分配或解分配特定存储单元的函数调用以单独全序出现,并且在此顺序中,每个解分配调用先发生于下个分配(若存在)。 |
(C++11 起) |
operator new
的库版本是否产生任何对 std::malloc 或 std::aligned_alloc (C++17 起) 的调用是未指定的。
对于加载大文件,经由如 POSIX 上的 mmap
或 Windows 上的 CreateFileMapping
(A
/W
) 伴随 MapViewOfFile
的操作系统特定函数进行文件映射,比为文件读取分配缓冲区更适合。
示例
本节未完成 原因:暂无示例 |
参阅
解分配函数 (函数) | |
(C++11) |
获得当前的 new 处理函数 (函数) |
注册一个 new 处理函数 (函数) | |
(C++17 中弃用)(C++20 中移除) |
获得未初始化存储 (函数模板) |
分配内存 (函数) | |
(C++17) |
分配对齐的内存 (函数) |
引用
- C++11 标准(ISO/IEC 14882:2011):
- 18.6 Dynamic memory management [support.dynamic]