У меня есть древовидная структура данных, которую я настроил так:
class Root; // forward declaration
class Tree {
public:
void addChildren(Root &r, ...) { childA = r.nodeSpace.allocate(); ... }
// tons of useful recursive functions here
private:
Tree *childA, *childB, *childC;
Tree *parent;
int usefulInt;
};
class Root : public Tree {
friend class Tree; // so it can access our storage
public:
private:
MemoryPool<Tree> nodeSpace;
};
Мне действительно нравится эта структура, потому что
- Я могу вызвать всетакже рекурсивные функции, определенные на
Tree
на Root
, без необходимости копировать и вставлять их. - Root владеет хранилищем, поэтому всякий раз, когда оно выходит из области видимости, именно так я определяю дерево какдольше действителен.
Но потом я понял проблему.Кто-то может случайно вызвать
Tree *root = new Root();
delete root; // memory leak! Tree has no virtual destructor...
Это не предназначенное использование (любое обычное использование должно иметь Root
в стеке).Но я открыт для альтернатив.Сейчас, чтобы решить эту проблему, у меня есть три предложения:
- Добавить виртуальный деструктор к
Tree
.Я бы предпочел не делать этого из-за издержек, так как дерево может иметь много-много узлов. - Не позволяйте
Root
наследовать от Tree
, но вместо этого пусть он определяет свой собственный Tree
член.Создает небольшую косвенность, не слишком страшную, все еще может вызывать тонны полезных рекурсивных функций в Tree
, выполняя root.tree().recursive()
. - Запрещать назначения, такие как
Tree *root = new Root();
.Я понятия не имею, возможно ли это или обескуражено или поощрено.Существуют ли конструкции компилятора? - Что-то еще?
Какой из них мне лучше выбрать?Большое спасибо!