本质上,当您使用如下新表达式时:T *t = new T;
,它大致相当于:
void *temp = operator new(sizeof(T));
T *t = new(temp) T;
因此,首先它使用分配函数分配一些原始内存,然后在该内存中构造一个对象。同样,当您使用如下删除表达式时:delete t;
,它大致相当于:
t->~T();
operator delete(t);
所以,如果你超载new
and delete
对于特定类别:
class T {
int data;
public:
// I've made these static explicitly, but they'll be static even if you don't.
static void *operator new(size_t size) {
return malloc(size);
}
static void operator delete(void *block) {
free(block);
}
};
然后,当您使用新表达式时,它将调用该类'operator new
分配内存,这将调用malloc
, so T *t = new T();
最终将通过分配内存malloc
(同样,当你delete
它,它将使用operator delete
,这将调用free
).
至少从通常使用的术语来看,分配器非常相似,只是它由容器而不是其他代码使用。它还将分配函数和删除函数封装到一个类中,因此当您将一个函数传递给容器时,只需传递一个对象,并且分配和删除函数不匹配的可能性很小。
暂时忽略有关事物名称的详细信息,即标准库中的 Allocator 类mostly做同样的事情,所以只需对函数中的函数进行一些重命名T
完成上面的课程后,您就已经完成了标准分配器的一半编写工作。为了配合分配和删除,它有一个函数rebind
一些内存(将内存块更改为另一种类型),就地创建一个对象(基本上只是围绕新放置的包装器)并销毁一个对象(同样,围绕析构函数调用的简单包装器)。当然,它使用operator new
and operator delete
代替malloc
and free
就像我上面用过的那样。