CuteAlien wrote:And calling it on each drop() would be even more wrong - because you have to be able to call drop() _without_ removing it from the SceneGraph (such things are more or less the reason to even have reference-counting).
I agree with it, but that is not the point.
CuteAlien wrote:Also calling setParent in the destuctor would be wrong because you should never call virtual functions in a destructor
CuteAlien wrote:edit: As an example - think about what would happen in the current ISceneNode::removeAll() when the child nodes would start deleting themselves from their parent in their destructor. That's why it wouldn't get safer or easier - just lead to another categorie of bugs (and slower code in this case to avoid the troubles).
These are not real problems. I agree that the code will be a bit slower, but since you don't add/delete scene nodes every frame, it is not a concern. What is possible is adding the following protected method to ISceneNode:
Code: Select all
protected:
virtual void removeChildrenFromDestructor(ISceneNode* c)
{
ISceneNodeList::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
if ((*it) == child)
{
Children.erase(it);
return;
}
}
Then, in the destructor:
Code: Select all
ISceneNode::~ISceneNode()
{
if(Parent)
Parent->removeChildrenFromDestructor(this);
Parent = 0;
// usual stuff
}
The parent will be informed that one of his children is not available anymore:
- if the parent is not being destroyed, then the virtual function call will call the (maybe) overriden function.
- if the parent is being destroyed, then it is a call to the ISceneNode::removeChildFromDestructor. That means the derived type is already deleted and
all variables pointing to children are that were defined in the derived class are not present anymore. In short, there are no references to children from derived parent object, since this layer was already deleted. The remaining references are in ISceneNode, and the called function can deal with them.
A call from removeAll() or removechild() will
not call removeChildFromDestructor(), since:
- parent call removeAll() or removeChild()
- node parent is set to 0 (current behavior)
- node get dropped
- node is deleted
- condition for calling removeChildFromDestructor() is not met : parent == 0...
I've done a simple example here:
http://codepad.org/MhVObi60
(with inheritance, I hope it is a bit readable. You can see the current Irrlicht implementation behavior here:
http://codepad.org/LJDpmXG0).
edit: forgot to say... since removeChildFromDestructor() is virtual, it is possible to reimplement it if your derived object stores additionnal references to children.