我可以使用不同的参数覆盖全局operator new
,例如我可以:
void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, int num) throw (std::bad_alloc);
可以单独调用
int* p1 = new int; // calls new(size_t)
int* p2 = new(5) int; // calls new(size_t, int)
因为每个都可能使用一些不同的分配方案,我需要为每个分配方案单独的delete()
函数。但是,delete(void*)
不能以相同的方式重载! delete(void*)
是唯一有效的签名。那么如何处理上述情况呢?
P.S。我并不是说这是一个好主意。这种事情发生在我身上,所以我在c ++中发现了这个“缺陷”(至少在我看来)。如果该语言允许new
覆盖,则必须允许delete
覆盖,否则它将变得无用。所以我想知道是否有办法解决这个问题,而不是这个好主意。
答案 0 :(得分:8)
我可以用不同的参数覆盖全局operator new
这些被称为展示位置分配函数。
delete(void *)是唯一有效的签名。
没有
首先,一些术语:删除表达式,例如delete p
不仅仅是一个函数调用,它调用析构函数然后调用解除分配函数,是operator delete
的一些重载,由重载决策选择。
您可以覆盖operator delete
并使用签名来匹配您的展示位置分配函数但只有在展示位置新表达式调用的构造函数时才会使用该重载引发异常,例如
struct E {
E() { throw 1; }
};
void* operator new(std::size_t n, int) throw(std::bad_alloc) { return new char[n]; }
void operator delete(void* p, int) { std::puts("hello!"); delete[] (char*)p; }
int main()
{
try {
new (1) E;
} catch (...) {
puts("caught");
}
}
放置释放函数与放置新表达式的形式相匹配(在这种情况下,它具有int
参数)通过重载解析找到并调用以释放存储。
因此,您可以提供“放置删除”功能,您无法明确地调用它们。您可以记住如何分配对象并确保使用相应的释放。
答案 1 :(得分:5)
如果您跟踪使用不同new
重载分配的不同内存区域,则可以使用调用的new
版本标记它们。
然后在delete
时,您可以查看地址,找到被调用的new
,并在每种情况下执行不同的操作。
通过这种方式,您可以保证正确的逻辑自动与每个不同的new
重载相关联。
正如baruch在下面的评论中所指出的那样,维护用于跟踪的数据会产生性能开销,只要重载的删除没有通过任何使用分配的任何内容传递,这个逻辑也会起作用。默认删除。
就跟踪开销而言,在我看来,跟踪分配类型的最小开销方法是分配所请求的数量,加上在分配区域的开始处的少量额外空间来标记请求类型(根据保守的对齐要求调整大小)。然后,您可以在删除时查看此标记区域,以确定要遵循的逻辑。
答案 2 :(得分:2)
是与展示位置运算符new匹配的展示位置删除。 你不能直接打电话。这是因为放置删除仅用于在新对象的构造函数抛出时释放内存。
void *operator new(size_t, Area&); // placement new
void operator delete(void*, Area&); // matching placement delete
...
Area &area;
SomeType *t=new(area) SomeType();
// when SomeType() throws then `delete(t,area)` from above is called
// but you can't do this:
delete (area) t;
解决这个问题的常用方法是使用write一个重载的“destroy”函数,该函数接受各种参数。
template<class T> void destroy(Area &a, T* &pt) //<-you can't do this with 'delete'
{
if (pt) {
pt->~T(); // run the destructor
a.freeMem(pt); // deallocate the object
pt=NULL; // nulls the pointer on the caller side.
}
}
答案 3 :(得分:0)
简单的答案是:不要这样做。所有形式的非放置new
在C ++ 11中都是多余的,并且非常不安全,例如,返回原始指针。如果要在自定义位置分配对象,则使用具有allocate
函数的类(如果有状态)或自由函数(如果不是)。 new
以及delete
的最佳处理方法是将其从偏见的程序中删除,placement new
除外。
编辑:原因为什么它对你没用是因为你试图将它用于不适合它的目的。所有你可以使用额外的参数来记录或其他行为控制。您无法真正更改new
和delete
的基本语义。如果您需要有状态分配,必须使用类。
答案 4 :(得分:-1)
你错了。 is possible提供展示位置删除。