Skip to main content
GameDev.net gamedev.net
🔒 Locked

c++ destructor help

Started by mackscynox Jul 12, 2004 at 2:16 AM 8 replies 850+ views
Original Post
mackscynox
mackscynox
i have written 2 classes, both of them has a pointer to other like a parent-child situation. on parent destruction all childs are destroyed one-by-one. the problem is on destruction of child it has something to do on its parent (also child has a pointer to its parent) but when calling its parent's any member the program fails with "abnormal termination" or something like that. i realized that the this occurs when the parent is destroyed because it tries to kill all childs and the child tries to modify its parent's some data and BOOM... the program terminates i know the problem but can you suggest me a solution? i know i didnot write the classes because they are so long (really) but imagine 2 classes like that i tried to first empty(delete) all childs then self-destruct but the classes' logic prevented this to be performed In my examples a child can die anytime but the parent only dies at program termination (maybe i couldnot explain it but offer me another solution) struct Child; struct Parent{ //all public , no matter Child* List[MAX]; int Childcount; ~Parent ( ){ for( int i =0 ; i ) delete List; } } }; struct Child{ //all public , no matter Parent * Mummy; ~Child ( ){ Mummy->ChildCount--; } }; NOTE: i wrote those classes to explain my problem , they may contain errors and i just wrote them in a few seconds
paulecoyote
paulecoyote
The parent child thing isn't really what they are as no inheritance seems to be going on. Rather they are aggregates.

I'd start by ensuring that your pointers to mummy are actually initalised properly. Ensure they are set to null until they are set to mummy. Also in your list make sure when a kid does tell the parent it's dead that it's removed and nulled from a list. Elementary things I know but gotchas for anyone who's been looking at the same code for too long.

Of course having a non-zero pointer value might not mean that mummy is still valid... kind of why it's best to avoid this kind of thing where possible. Although you say that the parent should never be killed before the kid - which is why I think somewhere the parent is keeping a reference to a deceased child.

I would question your assignment of responsibility too - do you really want your kid to boss around your mum? Surely the mum should be responsible for cleaning up after the children - and take care of its own counter. After all it knows when it's deleted the kid.

Can't really help much more 'cos the code you posted probably doesn't really properly reflect what is actually going on.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
snk_kid
snk_kid
Quote:
Original post by mackscynox
i have written 2 classes, both of them has a pointer to other like a parent-child situation.

on parent destruction all childs are destroyed one-by-one.
the problem is on destruction of child it has something to do on its parent (also child has a pointer to its parent) but when calling its parent's any member the program fails with
"abnormal termination"
or something like that.

i realized that the this occurs when the parent is destroyed because it tries to kill all childs and the child tries to modify its parent's some data and BOOM... the program terminates


That shouldn't happen because parent hasn't been completely been deconstructed, are you sure you have registered all the children to there parent?

Quote:
Original post by mackscynox
i know the problem but can you suggest me a solution?
i know i didnot write the classes because they are so long (really) but imagine 2 classes like that

i tried to first empty(delete) all childs then self-destruct but the classes' logic prevented this to be performed
In my examples a child can die anytime but the parent only dies at program termination (maybe i couldnot explain it but offer me another solution)


What do you mean all parents die at program termination? or you do you mean one parent, the root because it's statically allocated?

A couple of suggestions, instead of maintaining a fake list of children & child count why not use the standard library list which keeps count, then the children wouldn't need to decrement child count.

I don't understand why children are doing it anyways because the parent should be managing the child count besides.

Also the way your making a tree you don't need make a distinction between a child and a parent. This is how i think you should do it using the method as you are:

#include <cstddef>#include <algorithm>#include <list>template< typename T >class tree {   typedef tree<T>             _self;   typedef tree<T>             _child_type;   typedef tree<T>*            _child_ptr;public:   typedef T                   value_type;   typedef value_type*         pointer;   typedef const value_type*   const_pointer;   typedef value_type&         reference;   typedef const value_type&   const_reference;   typedef ::size_t            size_type;   typedef ::ptrdiff_t         difference_type;   typedef std::list<_child_ptr>  child_list_type;   typedef std::list<_child_ptr>::iterator child_iterator;   typedef std::list<_child_ptr>::const_iterator const_child_iterator;private:  child_list_type		_kids;  _child_ptr			_parent;  value_type			_item;  void parent(_child_ptr p) {     _parent = p;  }  //does deep copy provided T has a proper copy constructor  void _M_copy(const _self& t) {     for(child_iterator itr = t.kids.begin(),          end = t.kids.end();          itr != end;          ++itr) {           _child_ptr new_kid = new _child_type(*itr);           new_kid->parent(this);           this->_kids.push_back(new_kid);      }   }public:   tree(const T& i = T(), _child_ptr p = 0): _item(i), _parent(p), _kids() {}   tree(const tree<T>& t): _item(t._item), _parent(t._parent), _kids() {      _M_copy(t);   }   bool empty() const { return _kids.empty() }   _self& operator=(const _self& t) {       if(this != &t) {          if(!t.empty()) {             clear();             _parent = t._parent;             _item   = _item;             _M_copy(t);          }       }       return *this;   }   const_reference element() const { return _item; }   reference element() { return _item; }   size_type size() const { return _kids.size() }   void clear() {      _parent = 0;      for(child_iterator itr = _kids.begin(),          end = _kids.end();          itr != end;          ++itr) {          delete *itr;      }      _kids.clear();   }   ~tree() { clear(); }   void insert_child(const T& v) {      _child_ptr new_kid = new _child_type(v, this);      _kids.push_back(new_kid);   }};


I just write that i haven't compiled this and it's not complete it should give something to start with. Keep in mind there is a more efficient way of making a tree type than this method thou.

[Edited by - snk_kid on July 12, 2004 3:22:41 AM]
mackscynox
mackscynox
i have to explain some important issues now beacuse i see that i am misunderstood

1. in my examples or parent and child I DIDNOT WRITE THE CONSTRUCTORS KNOWINGLY because they have no importance but be sure that the pointers(and also everything) are initialized

2. MY real problem for classes is :

i make a modelization of a file system , and there exists 3 types of classes : _Base (abstract) _File , _Folder , _Shortcut.
(+) file has data (any type) also inherits _Base
(+) folder has a vector (stl) of _Base pointers , also inherits _Base (folder contents)
(+) shortcut has pointer to another _Base , also inherits _Base

now the _Base :
it has a vector of _Shortcut pointers named ShortcutTable. that is because whenever a _Shortcut is registered to a _File or _Folder type then this new _Shortcut's pointer is inserted into the ShortcutTable of the _Base type of _File or _Folder.
when the _Base is deleted instead of modifying the all _Shortcut classes' pointer that are in shortcut table they are deleted to maintain the stability. to prevent existence of NULL points _Shortcut object.
also to know where it is it has a pointer to a _Folder (the current folder)

i hope i explained my situation , now my problem:

whenever the folder is deleted all elements in it (files , subfolders and again also their subfolders, shortcuts to any ) are deleted. BUT if the next element to be deleted at destruction has some shortcuts in the same folder
ex: (order may change but think of this)
folder-> fold1
(-) file-> file1 , has data
(-) shortcut-> sc1 , points to file1

then first the destruction of file called and (only deletes its data) and successfull. but inherits _Base so calls destructor of _Base . the _Base destructor realizes that the object has some shortcuts assigned to it and to ensure stability it deletes all _Shortcut objects assigned to it too. the problem occurs here:
in _Shortcut destruction it modifies the folder contents vector (stl) and removes its' own pointer from the current folder contents (which is a vector< _Base* > ). BUT the destruction of that folder called already so BOOM. "Abnormal program termination"
i checked that if the destructor of _Base class doesnot destroys and deletes the shortcut objects assigned to it , no problem occurs but a nondeleted system resource still in memory-memory leak occurs.
i told you that the destruction of folder should empty its contents ON DESTRUCTION only (maybe before destruction by some means but WHAT ARE THESE MEANS I DO WANT TO KNOW)

i hope you now understood my problem.
if you have any long or hard solution please contact me

thanks for your interest and helps!
mackscynox
mackscynox
funnyly i also have created (only thought) a solution to my own problem :)
BUT :( it is very hard and may create new problems

at destruction of folder , the address stack (sth like the address bar you see in the explorer in windows,NOT IE) of each element can be get and check the folder pointer for all shortcut objects of elements in that folder but it is very long and hard.
ex: in my example the file1 has a shortcut of sc1 in same folder so first disable the shortcut by modifying its pointer to source to NULL and also remove the shortcut pointer from its source file's shortcut table

if you have improvements and may be a new solution please help?
snk_kid
snk_kid
I'm not sure if i completely understood what are trying to say, by the looks of things your using a composite pattern here. What i would suggest that you keep the composite structure and the shortcut type separate. Probably a good idea is with your parent-child structure use boost shared_ptr and have a link (the shortcut) type have a boost weak_ptr to them. Or even better is to use boost filesystem where you can create reference-counted hard links or non-reference-counted symbolic links.

EDIT: if your going to do this on your own then search for composite & flyweight patterns to help you here.
mackscynox
mackscynox
thanks for suggest snk_id but my aim is not to create a new file system but to create a multi-dimensional and self-linking container to be held in memory.
i need shortcuts because of not to make copies of same objects in several places because there will be only one original but many shortcuts to it and the main will be held in a temporary database like container and wont be deleted until all shortcuts of that are deleted

also what is this composite structure/composite pattern you specified? please explain?

snk_kid
snk_kid
Quote:
Original post by mackscynox
thanks for suggest snk_id but my aim is not to create a new file system but to create a multi-dimensional and self-linking container to be held in memory.
i need shortcuts because of not to make copies of same objects in several places because there will be only one original but many shortcuts to it and the main will be held in a temporary database like container and wont be deleted until all shortcuts of that are deleted

also what is this composite structure/composite pattern you specified? please explain?


It's not exactly a filesystem format suchs fat32, ext3, etc, it's the exact thing it can do from your description.

Patterns are generic can be applied to any situation that fits the problem you have. In short taken from GOF book:

A composite: Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual ojbects & compositions of objects uniformly.

Flywieght: Use sharing to support large numbers of fine-grained objects efficiently.

From what you just said now you can apply the flywieght pattern to share instances & it goes well with a composite pattern that sounds like the structure your using aswell. There are aloads of resource on the net about design patterns.
mackscynox
mackscynox
thanks again snk_kid , but i will need some time to understand what is going on in it.

if you have found a quick solution to my problem contact me before i change the structure of what i have done :)
paulecoyote
paulecoyote
Sure you've probably fixed it all by now, but if not could you post some Pseudo code of what the process you're actually using is?

One way would be to take an idea from the C# and Java worlds - and create a flag that determines what has caused the destructor to be called. That way it could behave differently if a folder tells it that it's being deleted, or if it's being deleted directly.

Are you using recursion to go through the object hierachy?

In a way it makes sense that a shortcut would be invalid and kick up a fuss if the folder has already gone.

What you might like to think about is employing the model-view-controller pattern. When a shortcut is created, it should register it's interest in that file / folder. That way if the file / folder is renamed, moved or destroyed - it can send a message to all those that registered interest - and those interested can keep themselves up to date, or even delete themselves.

Here is a pretty good example of an MVC - I'm sure if you look something may click.
http://sern.ucalgary.ca/courses/SENG/609.04/W98/lamsh/observerLib.html

Cheers,

Paul
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.