Quantcast
Channel: Cocos Forums - Latest topics
Viewing all articles
Browse latest Browse all 17070

Why removeFromParent()/removeChild() Could Be Dangerous?

$
0
0

@Joseph39 wrote:

OK i will rephrase the Question:

Why removeFromParent()/removeChild() could be dangerous in big heavy scenes?

we all know that nodes children are maintained inside a vector like this:

// brief version of CCNode.h
class Node: public Ref {
	...
	protected:
	cocos2d::Vector<cocos2d::Node*> _children;        ///< array of children nodes
	....
};

i will first start explaining the problem by digging into addChild() code. and we all know that when calling addChild() method to add a child node to a parent node this code gets triggered:

i will highlight only the important parts of the methods in here:

void Node::addChild(Node *child, int localZOrder, int tag)
{    
	...
    addChildHelper(child, localZOrder, tag, "", true);
	...
}

which as you see internally calls addChildHelper()

void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
{
	...
    this->insertChild(child, localZOrder);
	...
}

which internally calls insertChild()

void Node::insertChild(Node* child, int z)
{
	...
    _children.pushBack(child);
	...
}

which finally calls pushBack()

now that we know the implantation of addChild().let us assume that we are adding say 5000 node to a layer which is basically a node.

no problems wright! 5000 node will be added to the layer.

know lets assume that some nodes are dying and we have to use removeFromParent() to remove them, that should be simple write! ... Big No?

and in order to see whats happening loud and clear we'll have to dive in to the code one more time to illustrate the problem but this time its removeFromParent() code:

void Node::removeFromParent()
{
    this->removeFromParentAndCleanup(true);
}

internally calls removeFromParentAndCleanup()

void Node::removeFromParentAndCleanup(bool cleanup)
{
	_parent->removeChild(this,cleanup);
}

internally calls removeChild()

void Node::removeChild(Node* child, bool cleanup /* = true */)
{
	...
    this->detachChild( child, index, cleanup );
	...
}

internally calls detachChild()

void Node::detachChild(Node *child, ssize_t childIndex, bool doCleanup)
{
	...
    _children.erase(childIndex); // bad very bad idea
	...
}

which finally calls vectore::erase()

well it's not that bad until you realize that vectors are very bad at removing or inserting things other than the end.

still not convinced why its bad? OK, what if the dying node that we want to remove is in the middle of the vector or worse in the front of the vector. and combining that with the ugly truth of vectors which is every time an item is removed, all items after that one are moved/copied one position to the front and in the end you will simply get a disaster?!

knowing the fact that cocos2d relies heavily on the use of nodes imagine how many copies will be made in big scenes? or what will happen in a fast pace game?

you can read all about the consequences more in this article along with their proposed solutions just to widen your vision a bit:

so know as you see every time you call removeFromParent() it doesn't just remove it also shifts children elements. this is especially important on mobile devices where resources are limited (like cpu cycles) and too valuable to waste on unnecessary easy to avoid copying.

of course this won't hurt in small light weight scenes but in big projects with big scenes this might come back and bite you.

and you might justify its safety by the fact that pointers are cheap to copy i mean they are just 4 bytes in size in case of 32 bit machines and 8 bytes for 64 bit machines and your right they are cheap to copy and here is even a confirmation in this book which confirms it but still that's not an excuse for bad behavior at least not for me:
https://books.google.be/books?hl=ar&id=XclHqTM37UIC&q=copy+overhead#v=snippet&q=copy%20overhead&f=false

or you might justify its safety with the other fact that you can always override the default behavior but what about newcomers that are not fully aware of the risks of the default behavior and they will eventually pay for what they didn't buy.

one last thing even if this is not bad as i might think just why opening the door for a potential future performance bottlenecks and just why not be on the safe side of things and use a good future proof remove mechanism (as there are lots out there to choose from) as a default behavior that will work for small or big scenes without having to override ... why not do it even just for the sake of good design point of view.

P.S: This is a warning more than a question but i would like to hear your opinions on this matter and if it's worth a pull request?

Posts: 2

Participants: 2

Read full topic


Viewing all articles
Browse latest Browse all 17070

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>