关于内存管理:C ++和虚拟析构函数

C++ and virtual destructors

我正在一个应用程序中编写一个实用程序类,在这个应用程序中,它们可能是,也可能不是将来的派生。我没有任何虚拟函数(使用虚拟DTOR的一般准则),因此考虑到内存限制,我选择在这个实用程序类中不使用虚拟析构函数。

后来有几个程序员——有人从我的实用程序类中派生出了它。现在,如果在代码中的任何地方,我的新类在new'd中并删除了正确的dtor,则不会被调用,因为基类dtor不是虚拟的(参见示例代码)。

除了返回并更改基类-在这种情况下还有什么解决方案?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;

class utility {
  int i, j;

  public:
    utility () { cout <<"utility ctor
"
;};
   ~utility () { cout <<"utility dtor
"
;};
    void dosomething () { cout <<"haha
"
;};
};

class addtoutility: public utility  {
  char *ch;

  public:
   addtoutility () { ch= new char(); cout <<"added ctor
"
;};
  ~addtoutility () { delete ch; cout <<"added dtor
"
;};
   void andnowaddsomefunctionality () {};
};

int main () {
  utility *u  = new addtoutility();
  //lots of interesthing code
  delete u;
}


您的基类不是多态的,所以在任何情况下,拥有指向基的指针都没有什么价值。您的基类通过在任何地方不使用virtual关键字来记录它不是多态的事实。

如果有人想将它用作多orhpic层次结构的基类,那么他们可以将virtual析构函数添加到从它派生的第一个类中,并在必要时保留指向该基类类型的指针。

你不能阻止后来来的程序员挖掘自己的陷阱,但是非多晶硅类没有任何问题,你不需要做任何事情来"保证安全"。

作为证明这是一种常见且可接受的实践的证据,您只需查看标准库。有许多类(严格来说,大多数是类模板)没有虚拟函数,也没有虚拟析构函数。


  • 通过正确类型的指针删除它。因为其他方法都不是虚拟的,所以没有必要对其进行多态性处理。

作品:

1
2
3
addtoutility *u  = new addtoutility();

delete u;
  • 使其虚拟化。如果你担心开销,那么它很可能是微不足道的。
  • 使用crtp使用静态继承。唯一的问题是,这可能比vtable占用更多的内存。


如果根本无法修改基类的代码,可以向派生类添加函数,如destroy()。有点烦人,但如果您想到像Brush这样的win32对象,我们会一直这样做。