首先,举个例子:
#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释放内存
异常: up
未使用参数释放内存
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)
中给出的放置形式在此处推广为一个 表达式列表。对于特定的 new-expression,expression-list 中的每个 expression 都作为额外的参数传递给分配函数。如果调用构造函数时发生释放,将向释放函数传递相同的参数加上一个前导的 void*
(分配函数的返回值)。
[expr.new]/18 规定:
如果上述所述的对象初始化的任何部分通过引发异常终止,则已为该对象获取存储器,并且可以找到适当的释放函数,则在 new-expression 的上下文中调用释放函数以释放正在构造对象的内存,之后异常在继续传播。如果找不到明确匹配的释放函数,则传播异常不会导致释放对象的内存。 [注: 当所调用的分配函数未分配内存时,这是合适的;否则,可能会导致内存泄漏。 —— 结尾注释]
和 /21
如果 new-expression 调用了释放函数,则将从分配函数调用返回的值作为类型为 void*
的第一个参数传递。如果调用了放置释放函数,则将传递与使用 new-placement 语法指定的同样的附加参数。
并且 /20
A declaration of a placement deallocation function matches the declaration of a placement allocation function if it has the same number of parameters and, after parameter transformations, all parameter types except the first are identical. Any non-placement deallocation function matches a non-placement allocation function. If the lookup finds a single matching deallocation function, that function will be called; otherwise, no deallocation function will be called. If the lookup finds the two-parameter form of a usual deallocation function and that function, considered as a placement deallocation function, would have been selected as a match for the allocation function, the program is ill-formed. [Example:
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
— end example ]
回到[basic.stc.dynamic.deallocation]:
1.释放函数必须是类成员函数或全局函数;如果在除全局作用域以外的命名空间范围内声明释放函数,或在全局作用域中静态声明释放函数,则程序无效。
2.每个释放函数都应返回void
,其第一个参数应为void*
。释放函数可以有多个参数。
new
?是放置新变量的那种吗? - John Dibling