7

我可以用不同的参数覆盖全局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*)是唯一有效的签名。那么上述情况该如何处理呢?

PS我并不是说这是一个好主意。这种事情发生在我身上,所以我在 c++ 中发现了这个“缺陷”(至少在我看来)。如果语言允许new覆盖,它必须允许delete覆盖,否则它变得无用。所以我想知道是否有办法解决这个问题,而不是这是一个好主意。

4

5 回答 5

8

我可以用不同的参数覆盖全局运算符 new

这些被称为布局分配函数

delete(void*) 是唯一有效的签名。

不。

首先,一些术语:一个delete 表达式例如delete p不仅仅是一个函数调用,它调用析构函数然后调用一个释放函数,这是operator delete由重载决议选择的一些重载。

可以使用签名覆盖operator delete以匹配您的放置分配函数,只有在放置 new 表达式调用的构造函数引发异常时才会使用该重载,例如

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由重载决议找到并调用以释放存储空间。

因此,您可以提供“放置删除”功能,只是不能显式调用它们。您需要记住如何分配对象并确保使用相应的解除分配。

于 2012-07-11T12:23:24.143 回答
5

如果您跟踪使用不同重载分配的不同内存区域,则可以使用调用new的版本标记它们。new

然后delete有时您可以查找地址以查找new被调用的地址,并在每种情况下执行不同的操作。

这样,您可以保证正确的逻辑自动与每个不同的new重载相关联。

正如巴鲁克在下面的评论中指出的那样,维护用于跟踪的数据会产生性能开销,并且只要重载删除未传递使用默认删除分配的任何内容,此逻辑也将起作用。

至于跟踪开销,在我看来,跟踪分配类型的最小开销方法是分配请求的数量,加上在分配区域开始时标记请求类型的少量额外空间(尺寸根据保守的对齐要求)。然后,您可以在删除时查看此标记区域以确定要遵循的逻辑。

于 2012-07-11T11:32:41.623 回答
3

有一个与放置操作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; 

克服这个问题的一种常见方法是使用编写一个重载的“销毁”函数,该函数接受各种参数。

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.
 }
} 
于 2012-07-11T12:05:03.327 回答
0

简单的答案是:不要这样做。所有形式的非放置new在 C++11 中都是多余的并且非常不安全,例如,返回原始指针。如果您想在自定义位置分配对象,那么如果有状态则使用带有allocate函数的类,否则使用自由函数。new实际上,最好的处理方法delete是将它们从您的程序中删除,但可能存在偏见,但placement new.

编辑:它对你没用的原因是因为你试图将它用于它不打算用于的目的。您可以将额外参数用于日志记录或其他行为控制之类的东西。你不能真正改变newand的基本语义delete。如果你需要有状态的分配,你必须使用一个类。

于 2012-07-11T12:14:49.380 回答
-1

你错了。可以提供展示位置删除

于 2012-07-11T12:05:15.477 回答