views:

109

answers:

5

I'm writing a class that holds a pointer to a parent object of the same type (think Qt's QObject system). Each object has one parent, and the parent should not be destroyed when a child is destroyed (obviously).

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
}

(Excuse my inline coding, it's only for brevity)

Will destroying the "Master MyClass" take care of all children? No child should be able to kill it's parent, because I would then have pointers in my main program to destroyed objects, correct?

Why might you ask? I need a way to "iterate" through all subdirectories and find all files on a platform independent level. The creation of this tree will be handled by native API's, the rest won't. Is this a good idea to start with?

Thanks!

A: 

Will destroying the "Master MyClass" take care of all children?

Yes how you have it coded it will. You may however wish to initialize a_children to NULL or to some space in memory you have preallocated.

Why might you ask? I need a way to "iterate" through all subdirectories and find all files on a platform independent level. The creation of this tree will be handled by native API's, the rest won't. Is this a good idea to start with?

Seeks ok so long as you have taken into account the case where someone external to your parent/child tree has a pointer to a child when the parent is deleted (resulting in the child being deleted). Will/can this be handled gracefully? Is this a situation you have to be concerned with? If so then you may have to think about dangling pointers.

Doug T.
A: 

I'm not a C++ expert but I don't think it's kosher to delete[] the children if they weren't allocated with new[].

See the C++ FAQ on memory allocation for more details.

However, otherwise, the plan looks sound.

Mr. Shiny and New
+4  A: 

This concept is fine, but there are a number of things wrong with the code you posted (although I gather from your comment about "inline coding" that you just wrote this on the fly rather than copying it out of a compilable program).

  1. You will need to have a_children be an array of MyClass pointers, so it will need to have type MyClass**, and you will need to allocate it an reallocate it appropriately as children are added.

  2. delete[] a_children will not delete the children, it will delete the array that holds the pointers to the children. You must, in the MyClass destructor, iterate over the array, deleting each child pointer, and then delete the array. In fact, it would probably be a better idea to use a std::vector<MyClass*> for a_children instead of MyClass*, so then you don't have to worry about (1). But even with a vector, you will still need to iterate and delete each child in the destructor.

  3. Your children will need to "register" with their parent object somehow. The way you have written this, there is no way for the child object to tell the parent object that it exists. For this reason you probably will not be able to get away with passing a const parent pointer.

So, as an example:

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;
};

Note that this does not take into account the possibility that children will be destroyed by any means other than destroying their parent.

Tyler McHenry
+1 for replacing dynamic array of children with `vector`.
Brian
The vector crossed my mind, but seemed illogical since many MyClass objects would have an empty children list (these would resemble files in the tree). But a vector it is :).The parent notification is also a good idea, didn't think that through yet :sSo: vector+parental knowledge it is. Thanks!
rubenvb
+2  A: 

Yes, if you create the children with:

a_children = new Myclass[sz_numChildren];

deleting a parent will in turn delete all children.

However, this will not be very flexible for a few reasons.

  • Children will have to be created all at once in a contiguous array. You won't be able to implement a function like addChild() very easily.
  • You will not be able to derive from MyClass and store the derived types as children since they are not being stored as pointers.

I would recommend using a vector of pointers to MyClass objects to store the children:

std::vector<MyClass*> a_children;

Then you can create children as needed:

a_children.push_back(new MyClass(parent));

and delete all children with:

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

The actual vector of pointers will be destroyed automatically.

Jason
A: 

Another gotcha is that you must make sure that an instance cannot be a child of more than one parent, or else destroying a parent could also destroy children belonging to another parent. In your example, a child directory could be a subdirectory of more than one parent directory due to hard links, Windows junction points or the like, so you need to either make sure that in such a situation each superdirectory would get its own unique child instance for that directory. If children can be shared, then you will need to implement some sort of reference counting scheme to prevent premature deletion.

Christopher Barber