析构函数与重载 delete 运算符

4

拥有析构函数和重载delete函数的目的是什么?

有哪些情况下应该同时使用它们?

4个回答

5
当您使用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关键字,它们也将是静态的。

3
一旦你意识到构造函数/析构函数和new/delete操作符的作用不同,答案就变得清晰明了:
- 构造函数和析构函数使你的类控制所拥有资源的获取和释放过程,但不包括对象本身的内存。 - new和delete操作符使你的类控制所分配实例自身的内存的获取和释放过程。
同时,你需要认识到new和delete操作符的调用包围着构造和析构函数的调用:new在构造函数之前发生,delete在析构函数之后发生。虽然析构函数可能把对象内容视为“活的”,但是delete操作符必须把它视为“死的”;特别是,在delete中尝试引用任何成员或调用类的任何成员函数都是未定义的。
现在答案应该是明确的:根据程序想要控制的内容,你可以实现其中一个或两个。

1
据我理解,析构函数旨在实现类特定的行为,如分配的资源的释放等,而重载delete运算符旨在进行自定义内存管理,这不是特定于类或仅针对一个类的如此描述。通常情况下,不需要重载newdelete

0

析构函数用于销毁类的实例(对象),无论它是作为自动变量在堆栈上分配的,还是使用new运算符在堆上分配的。

重载的newdelete仅在代码使用newdelete运算符分配内存时才会被使用。

请注意,newdelete是静态的,并且与void(非结构化)内存一起工作。它们不能通过(隐式或显式)this访问类的成员。您可以将此内存转换为对象并初始化/重置它,但不应该这样使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接