2010-05-18 3 views
1

Я пишу класс, содержащий указатель на родительский объект того же типа (подумайте о Qt-системе Qt). Каждый объект имеет один родительский элемент, и родительский объект не должен быть уничтожен, когда ребенок уничтожается (очевидно).Схема родительского ребенка

class MyClass 
{ 
public: 
    MyClass(const MyClass* ptr_parent): parent(parent){}; 
    ~MyClass(){ delete[] a_children; }; 
private: 
    const MyClass* ptr_parent; // go to MyClass above 
    MyClass* a_children; // go to MyClass below 
    size_t sz_numChildren; // for iterating over a_children 
} 

(простите мой инлайн кодирование, это только для краткости)

Будет разрушив «Мастер MyClass» заботиться о всех детях? Ни один ребенок не должен уметь убивать своего родителя, потому что тогда у меня были бы указатели в моей основной программе для уничтожения объектов, правильно?

Почему бы вам не спросить? Мне нужен способ «итерации» через все подкаталоги и поиск всех файлов на независимом от платформы уровне. Создание этого дерева будет обрабатываться встроенными API, а остальное - нет. С чего начать?

Спасибо!

ответ

4

Эта концепция в порядке, но с кодом, который вы опубликовали, есть ряд вещей (хотя я собираюсь из вашего комментария о «встроенном кодировании», что вы только что написали это «на лету», а не копируете его из компилируемого программа).

  1. Вам нужно будет иметь a_children быть массивом MyClass указателей, так что нужно будет иметь тип MyClass**, и вам нужно будет выделить ему перераспределить его соответствующим образом, как добавляются дети.

  2. delete[] a_children не удаляет детей, он удалит массив, содержащий указатели на дочерние элементы. Вы должны в деструкторе MyClass перебирать массив, удаляя каждый дочерний указатель, а затем удалять массив.На самом деле, вероятно, было бы лучше использовать std::vector<MyClass*> для a_children вместо MyClass*, так что вам не о чем беспокоиться (1). Но даже с помощью вектора вам все равно придется выполнять итерацию и удаление каждого дочернего элемента в деструкторе.

  3. Ваши дети должны будут как-то «зарегистрировать» свой родительский объект. Как вы это написали, нет способа, чтобы дочерний объект указывал родительскому объекту, что он существует. По этой причине вы, вероятно, не сможете уйти с передачей указателя родителя const.

Так, в качестве примера:

class MyClass { 

public: 

    MyClass(MyClass* parent) 
    : m_parent(parent) 
    { 
    if (m_parent) m_parent->registerChild(this); 
    } 

    ~MyClass() 
    { 
    for (std::vector<MyClass*>::const_iterator i = m_children.begin(); 
     i != m_children.end(); ++i) 
    { 
     delete *i; 
    } 
    } 

    void registerChild(const MyClass* child) 
    { 
    m_children.push_back(child); 
    } 

private: 

    MyClass* m_parent; 
    std::vector<const MyClass*> m_children; 
}; 

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

+0

+1 для замены динамического массива детей на «вектор». – Brian

+0

Вектор перешел мне в голову, но казался нелогичным, так как многие объекты MyClass имели бы пустой список детей (они бы напоминали файлы в дереве). Но вектор это :). Родительское уведомление также является хорошей идеей, не думал, что пока: s Итак: вектор + родительское знание. Благодаря! – rubenvb

0

Уничтожит «Мастер MyClass» позаботится обо всех детях?

Да, как вы его закодировали. Однако вы можете инициализировать a_children до NULL или к некоторому пространству в памяти, которое вы предварительно выделили.

Почему бы вам не спросить? Мне нужно, чтобы «итерации» через все подкаталоги и найти все файлы на платформе независимый уровень. Создание это дерево будет обработано родным API, остальное не будет. Является ли это хорошей идеей ?

Искряется до тех пор, пока вы учли случай, когда у кого-либо, внешнего по отношению к родительскому/дочернему дереву, есть указатель на дочерний элемент, когда родитель удален (в результате чего ребенок удаляется). Будет ли это обрабатываться изящно? Это ситуация, о которой вы должны беспокоиться? Если это так, вам, возможно, придется подумать об оборванных указателях.

0

Я не эксперт на С ++, но я не думаю, что это кошерно для delete[] детей, если они не были выделены new[].

Для получения более подробной информации см. the C++ FAQ on memory allocation.

Однако в противном случае план выглядит здоровым.

2

Да, если вы создаете детей:

a_children = new Myclass[sz_numChildren]; 

удаление родителя в свою очередь, удалить все дети.

Однако это не будет очень гибким по нескольким причинам.

  • Дети должны быть созданы все сразу в непрерывном массиве. Вы не сможете легко реализовать такую ​​функцию, как addChild().
  • Вы не сможете получить MyClass и хранить производные типы в качестве детей, так как они не сохраняются в качестве указателей.

Я бы рекомендовал использовать вектор указателей на MyClass объектов для хранения детей:

std::vector<MyClass*> a_children; 

Тогда вы можете создать ребенок по мере необходимости:

a_children.push_back(new MyClass(parent)); 

и удаления всех детей:

for(int i=0; i<a_children.size(); i++) 
    delete a_children[i]; 

Фактический вектор точки ers будут уничтожены автоматически.

0

Еще одна проблема заключается в том, что вы должны убедиться, что экземпляр не может быть дочерним числом более одного родителя, иначе уничтожение родителя может также уничтожить детей, принадлежащих другому родителю. В вашем примере дочерний каталог может быть подкаталогом более чем одного родительского каталога из-за жестких ссылок, точек соединения Windows и т.п., поэтому вам нужно либо убедиться, что в такой ситуации каждый суперкаталог получит свой собственный уникальный дочерний экземпляр для этого каталога. Если дети могут быть разделены, тогда вам нужно будет внедрить какую-то схему подсчета ссылок, чтобы предотвратить преждевременное удаление.

Смежные вопросы