当您使用
new
表达式分配对象时,例如:
X *x = new X();
它基本上执行两个不同的操作:首先分配内存,然后在该内存中创建一个对象,大致相当于:
void *temp = operator new(sizeof(X));
X *x = new(temp) X;
第一个函数只是分配了一块原始内存。第二个函数则将该块原始内存取出,并在其中创建一个对象。
大致上,当你删除一个对象时,相反的过程发生了:
delete x;
...大致相当于:
x->~X();
operator delete(static_cast<void *>(x));
因此,operator new和operator delete只处理分配和释放原始内存。构造函数和析构函数只处理在已经分配的内存中创建和销毁对象。在析构函数运行以销毁某个内存中的对象之后,然后使用operator delete来释放内存本身。
默认情况下,有一对全局的operator new和operator delete用于分配所有类型的对象。如果需要,可以替换它们。您还可以为特定类提供operator new和operator delete(作为静态成员函数)。在这种情况下,这些函数仅用于管理该类对象的内存。这对于像非常小的类之类的东西特别有用,并且您希望分配大量此类对象。许多内存管理器在处理大量极小的项目时效率不高,因此在这种情况下重载可以显著改善(减少)内存使用量。
还有operator new[]和operator delete[],用于分配/释放对象数组。operator new[]只传递要分配的字节数,而operator delete[]只传递一个要释放的原始内存块。如果决定重载这些内容,则可能认为它们主要用于更大的内存块并进行适当的优化,但这是与非数组版本的唯一区别。
作为规则,我会避免使用new来分配数组(永远),从而使它们完全无关。如果创建类似于std :: vector 的内容,则它们不能/不会被分配器使用。好吧,我想,如果您不介意彻底滥用系统,您可以创建一个用于std :: vector的分配器,该分配器使用new char [size]来管理分配,在这种情况下,它将使用其中之一,但我很难想象有人真的会这样做。也许在C ++不被很好理解的时候,但现在在任何体面的代码库中都会很明显。
注:一个微小的奇怪之处:编译器“知道”这些必须始终是静态的,因此即使您在声明/定义它们时不使用static关键字,它们也将是静态的。