Где удалить? - PullRequest
       2

Где удалить?

0 голосов
/ 03 февраля 2011

Мне довольно трудно выбрать лучший способ удалить мои производные классы здесь.В настоящее время у меня есть следующий макет:

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() вместо одного, объединенного в суперкласс.

Тогда мне стало интересно, начинаю ли я уже плохо с уровня проектирования, предполагая, что все передается в сложные типы TagCompound, а TagList является кучей объектом, к которому я тоже не могне может найти лучшего решения, потому что вся эта конструкция является частью синтаксического анализатора для чего-то, что выглядит следующим образом (просто двоичный, а не многословный):

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 ]

5 голосов
/ 03 февраля 2011

Как правило, вы просто объявляете виртуальный деструктор в базовом классе .Это хорошо сочетается с распределением стека и кучи.В случае полиморфного удаления компилятор выясняет истинный тип и вызывает его деструктор.

1 голос
/ 03 февраля 2011

C ++ предлагает очень элегантное решение для этого - виртуальный деструктор. Более того, каждый полиморфный тип должен иметь его. GCC даже имеет уровень предупреждения для этого -Wnon-virtual-dtor.

1 голос
/ 03 февраля 2011

Этот дизайн действительно нарушает идею инкапсуляции.Tag никогда не должен знать, что TagByte существует.Деструктор для Tag должен быть помечен как виртуальный, как и деструктор каждого производного класса.Отпустите выделенные переменные для каждого уровня в соответствующем деструкторе.При уничтожении все будет вычищено в правильном порядке без утечек памяти.У меня такое чувство, что этот дизайн с самого начала плох, и вы должны прочитать о деструкторах и наследовании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...