首先,一个例子:
#include <cstddef>
#include <iostream>
struct S
{
S(int i) { if(i > 42) throw "up"; }
static void* operator new(std::size_t s, int i, double d, char c)
{
std::cout << "allocated with arguments: "
<<i<<", "<<d<<", "<<c<<std::endl;
return new char[s];
}
static void operator delete(void* p, int i, double d, char c)
{
std::cout << "deallocated with arguments: "
<<i<<", "<<d<<", "<<c<<std::endl;
delete[] (char*)p;
}
static void operator delete(void* p)
{
std::cout << "deallocated w/o arguments"<<std::endl;
delete[] (char*)p;
}
};
int main()
{
auto p0 = new(1, 2.0, '3') S(42);
S* p1 = nullptr;
try
{
p1 = new(4, 5.0, '6') S(43);
}catch(const char* msg)
{
std::cout << "exception: "<<msg<<std::endl;
}
delete p1;
delete p0;
}
输出:
分配参数:1、2、3
分配有参数:4、5、6
使用参数解除分配:4、5、6
例外:向上
无参数释放
operator new 重载的规范定义是void *operator new(std::size_t, heap h)
我不明白这是怎么回事,因为这是不允许的:
好的,现在它是new 的有效放置形式:)
[basic.stc.dynamic.allocation]/1
分配函数应该是类成员函数或全局函数;如果分配函数在全局范围以外的命名空间范围内声明或在全局范围内声明为静态,则程序是格式错误的。返回类型应为void*。 第一个参数的类型应为std::size_t。第一个参数不应有关联的默认参数。 第一个参数的值应解释为请求的分配大小。
[强调我的]
您可以为new 的放置形式重载要调用的分配函数,请参阅[expr.new](对于非模板函数,[basic.stc.dynamic.allocation] 中没有明确允许,但是也不禁止)。 new(placement) 中给出的位置在这里被概括为一个表达式列表。 expression-list 中针对特定 new-expression 的每个 expression 作为附加参数传递给分配函数。如果释放函数被调用(例如,因为被调用的 ctor 抛出异常),相同的参数加上前导 void*(分配函数的返回值)被传递给释放函数。
[expr.new]/18 状态:
如果上述对象初始化的任何部分因抛出异常而终止,则已获得对象的存储空间,并且可以找到合适的释放函数,则调用释放函数以释放对象所在的内存构造,之后异常继续在 new-expression 的上下文中传播。如果找不到明确匹配的释放函数,则传播异常不会导致对象的内存被释放。 [注意: 这适用于被调用的分配函数不分配内存的情况;否则,很可能导致内存泄漏。 — 尾注 ]
和/21
如果 new-expression 调用释放函数,它会将分配函数调用返回的值作为void* 类型的第一个参数传递。如果调用了放置解除分配函数,它会传递与传递给放置分配函数相同的附加参数,即与使用 new-placement 语法指定的参数相同。
和/20
如果布局释放函数的声明具有相同数量的参数,并且在参数转换后,除第一个之外的所有参数类型相同,则布局释放函数的声明与布局分配函数的声明相匹配。任何非布局释放函数都匹配非布局分配函数。如果查找找到一个匹配的释放函数,则调用该函数;否则,不会调用释放函数。如果查找找到通常释放函数的双参数形式,并且该函数被认为是放置释放函数,将被选为分配函数的匹配项,则程序是非良构的。 [例子:
struct S {
// Placement allocation function:
static void* operator new(std::size_t, std::size_t);
// Usual (non-placement) deallocation function:
static void operator delete(void*, std::size_t);
};
S* p = new (0) S; // ill-formed: non-placement deallocation function matches
// placement allocation function
— 结束示例 ]
回到[basic.stc.dynamic.deallocation]:
1 释放函数应为类成员函数或全局函数;如果释放函数在全局范围以外的命名空间范围内声明或在全局范围内声明为静态,则程序是非良构的。
2 每个释放函数应返回void,其第一个参数应为void*。一个释放函数可以有多个参数。