在哪里删除?

时间:2011-02-03 04:07:47

标签: c++ oop

我很难在这里决定删除派生类的最佳方法。我目前有以下布局:

class Tag {
   // Stuff
   // [...]
   void releaseMemory(Tag *t);
};

class TagByte : public Tag { /* [...] */ };
class TagShort : public Tag { /* [...] */ };

Tag::releaseMemory(Tag *t) {
    switch (t->getType()) {
       case TAG_BYTE:  delete (TagByte *)t; return;
       case TAG_SHORT: delete (TagShort *)t; return;
       // [...] many more
    }
}

我这样做的原因是有更复杂的标签,如TagCompound,它们将包含不同类型的标签,所有标签都存储为Tag *。在析构函数~TagCompound~TagList内,我会在每个标记上调用Tag::releaseMemory();,因为delete上的Tag *只会释放Tag而不会实际的TagWhatever,从而导致内存泄漏。

我想到的另一个选择是为每个派生类添加一个新的虚拟方法,因此Tag的每个孩子都拥有它自己的releaseMemory()而不是超类中的一个。

然后我想知道我是否已经在设计级别上开始变坏,假设传递到复杂类型TagCompoundTagList的所有内容都是对象我也找不到更好的解决方案,因为整个构造是解析器的一部分,看起来像这样(只是二进制而不是冗长):

TAG_Compound("Root"): 4 entries
{
  TAG_String("Name"): Test
  TAG_Short("SomeNumber"): 21
  TAG_Double("..."): 9000.5
  TAG_Compound("Eek!"): 2 entries
  {
    TAG_String("Marco"): Polo
    TAG_List("Names"): 3 entries of type String
    {
      TAG_String: Hello
      TAG_String: World
      TAG_String: Segfault
    }
  }
}

在运行时动态读取它并不能很好地与堆栈上的实例一起使用。

我能做些什么......我不知道......优雅?

3 个答案:

答案 0 :(得分:5)

通常,您只需declare a virtual destructor in the base class。这对堆栈和堆分配都很好。在多态删除的情况下,编译器会计算出真实类型并调用其析构函数。

答案 1 :(得分:1)

这种设计确实打破了封装的想法。 Tag永远不会知道TagByte存在。 Tag的析构函数应该被标记为虚拟,就像每个派生类的析构函数一样。在适当的析构函数中释放每个级别的已分配变量。在销毁时,一切都将以正确的顺序清理,没有内存泄漏。我的感觉是这个设计从一开始就很糟糕,你应该阅读析构函数和继承。

答案 2 :(得分:1)

C ++实际上为此提供了非常优雅的解决方案 - 虚拟析构函数。更重要的是,每种多态类型都应该有一种。 GCC甚至对此-Wnon-virtual-dtor有警告级别。