How to avoid a crash when when a node is deleted in update loop? (see example for clarification)

Hi,
let me wright this pseudo code first and then explain. Say GameScene is a game level. GameScene has a private Sprite member called _mySprite declared in the header as nullPtr. In the update method I am trying to print something if the sprite exist, and then delete that sprite.

bool GameScene::init()
{
    //... code
    _mySprite = Sprite::create("someTexture.png") ; 
    _mySprite->setPosition(500, 500);
    addChild(_mySprite);
    //... code
}

void GameScene::update(float dt)
{
	if (_mySprite)
	{
		CCLOG("check point A");
		_mySprite->removeFromParentAndCleanup(true);
	}
}

And this is the error

check point A
check point A
Exception thrown: read access violation.
this->_testSprite->**** was 0xDDDDDDDD.

My understanding is that 0xDDDDDDDD means that the pointer is null since I removed it with removeFromParentAndCleanup(true), right? But if I set the condition to enter the scope only if _testSprite exist (if (_mySprite)), why is it entering again after remove it?

My solution is to create a vector holding that sprite, and if I remove it, I delete it from the vector and the insteado of (if (_mySprite)), I do something like (if (myVector.size() > 0)). Or maybe using tags, but I wonder why my attempt on checking if a pointer isn’t null is not working. How would you approach something like that?

Thanks

That removes it from its parent, but it doesn’t clear the _mySprite variable. Whatever that variable is pointing to is no longer valid, which is what this means:

If it was null, then it would throw a different error related to de-referencing a null pointer. That is also why if (_mySprite) is not catching it, because it’s never null.

You should be doing this:

_mySprite->removeFromParentAndCleanup(true);
_mySprite = nullptr;

You should actually be calling retain explicitly on any Ref instance (such as a Sprite) if you’re holding it in a storage type that doesn’t track the ref count. For example, if you hold it in a class member variable, or in a std::vector, there is no way to be sure the pointers they are holding are valid. That is why you would explicitly call retain on creation, and then release when you’re done with the instance. Alternatively, you can use the cocos containers, such as cocos2d::Vector, which automatically call retain and release, ensuring that the instances they point to are always valid as long as they are in the container.

So, for example, your code should be like this:

_mySprite = Sprite::create("someTexture.png") ;
_mySprite->retain();
_mySprite->setPosition(500, 500);
addChild(_mySprite);

Then later on when you’re done with it:

_mySprite->removeFromParentAndCleanup(true);
_mySprite->release();
_mySprite = nullptr;

// OR you can use the CC_SAFE_RELEASE_NULL macro, which does the same thing:
_mySprite->removeFromParentAndCleanup(true);
CC_SAFE_RELEASE_NULL(_mySprite);
1 Like

Thanks a lot. That’s it.
Cheers.