EXC_BAD_ACCESS While Trying to Get Data from List or Vector

Hi, first of all, hadn’t been using C++ for years until recently. What I am trying to do is using a list of objects created from a struct that I created and rendering them inside update function.

My struct is simple as follows;

struct tlEntry{
            cocos2d::Sprite* s;
            int yPos;

Depending on the yPos they got, I want to add the sprite to the viewport. When I try to get the node from the list and try to do following, I get EXC_BAD_ACCESS error;


What am I doing wrong?

Have you stepped through the code with a debugger? It not, do so, and you’ll find the problem pretty quickly.

It’s most likely an issue with the sprite being created, added to the struct, and that struct added to a container, without ever calling retain() on the sprite. Read up on the retain()/release() combination, because if you’re not using it, then that would be the problem.

Hi @R101, thanks for the reply. I will read about retain()/release(). I thought they’d be used only if I used ccArray.

I stepped through the code. Sprite gets created and it’s not pointing NULL.

The sprite pointer being NULL is not the problem, but rather that it’s pointing to invalid memory, because the sprite has already been released. It’s an auto-release object, so if nothing calls retain on it to increase the reference count by 1 (see class Cocos2d::Ref), then on the next update loop it will be deleted by the PoolManager.

Assuming that is the issue, you would fix it like this:

std::vector<tlEntry> spriteEntries;

// Create sprite
tlEntry entry;
entry.s = Sprite::createXYZ() // Whatever creation method you want to use. Reference count = 1 here, and it is added to the auto-release pool (via a call to autorelease() in the create method)
entry.s->retain(); // retain the sprite, so increases ref count by 1, so now ref count = 2

Now say you’ve reached the end of this, and we’re on the next update loop.
Director::mainLoop() calls PoolManager::getInstance()->getCurrentPool()->clear(); to release all objects in the pool
The PoolManager checks the auto-release object collection, and for each item, it decrements the reference count by 1.
So, for this sprite, ref count = 2 - 1 = 1
The PoolManager then checks if ref count == 0, and if it is, it calls object->delete(). In this case, the sprite still has a ref count of 1.
All objects in the auto-release pool collection are removed, so they will no longer automatically checked in future updates

At this point the sprite you created has a ref count = 1. The only way this sprite can be removed and memory associated with it properly freed is to call release() on it, which is what you are responsible for.

So, when you no longer need the sprite in the list, you do this:
addChild(entries.front().s); // sprite added to a parent, which calls retain() on it, so now ref count = 2.

// At any point you want to remove the sprite/sprites from the list, you cannot simply call std::vector::clear(). You need to call release on all of the sprite first, then clear the list

for (auto&& entry : spriteEntries)

If you just want to remove 1 sprite from the list, for instance, the entry at the end, then do this:

auto entry = spriteEntries.pop_back(); // Removes the entry from the list
entry.s->release(); // Release/free the sprite. You can also call CC_SAFE_RELEASE_NULL(entry.s) or CC_SAFE_RELEASE(entry.s) instead
1 Like