c++cocos2d-xcocos2d-x-3.0

BAD ACCESS error when accessing method of vector element from touch callback


I have a class structure as follows:

class A
{
 public:
     virtual void func() = 0;
};

class B : public A
{
 public:
     virtual void func();
};

and I have provided an implementation for B's func in the corresponding .cpp file.

void B::func()
{
     cocos2d::log("Hello");
}

Now, when I try to access func of B from another file as follows:

class XYZ
{
 public:
    public void func2();
 protected:
    cocos2d::EventListenerTouchOneByOne * _Listener = nullptr;
    std::vector<A *> _List;

    bool touchBeginCallback(cocos2d::Touch *touch, cocos2d::Event *event);
    void touchEndCallback(cocos2d::Touch *touch, cocos2d::Event *event);
};

In XYZ.cpp

void XYZ::func2()
{
    _List.push_back(new B());
    _List.push_back(new B());
    _List.push_back(new B());
    _List.push_back(new B());
    _List.push_back(new B());

    for(auto itr = _List.begin(); itr != _List.end(); itr++)
    {
        A * a = (*itr);
        if(a)
        {
            a->func(); // Here it works fine
        }
    }

    _Listener = cocos2d::EventListenerTouchOneByOne::create();
    _Listener->setSwallowTouches(true);
    _Listener->onTouchBegan = (cocos2d::EventListenerTouchOneByOne::ccTouchBeganCallback) CC_CALLBACK_2(XYZ::touchBeginCallback, this);
    _Listener->onTouchEnded = (cocos2d::EventListenerTouchOneByOne::ccTouchCallback) CC_CALLBACK_2(XYZ::touchEndCallback, this);

    cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(_Listener, this);
}

bool XYZ::touchBeginCallback(cocos2d::Touch *touch, cocos2d::Event *event)
{
    return true;
}

void XYZ::touchEndCallback(cocos2d::Touch *touch, cocos2d::Event *event)
{
    for(auto itr = _List.begin(); itr != _List.end(); itr++)
    {
        A *a = (*itr);
        if(a)
        {
            a->func(); // Throws bad access error
        }
    }
}

The func() call (or rather accessing object of type B) works fine if I call it from a method in XYZ, but crashes with BAD_ACCESS error if I call it from touchEndCallback method.

When I checked _List in debug mode within func2(), it correctly showed that _List had five members of type B, but when I checked the list within touchEndCallback method, it showed that _List had five members of type A.

Why is this crash happening and how can I fix it?


Solution

  • Dereference the iterator to get the pointer A*. The loop should look like this:

    for(auto itr = _List.begin(); itr != _List.end(); itr++)
    {
        if (*itr)
            (*itr)->func();
    }
    

    or you can use range for:

      for(auto pa : _List)  // now you're gettting A* 's directly
        {
            if (pa)
               pa->func();    
        }
    

    EDIT: Using raw pointers is also bad idea. consider unique_ptr or shared_ptr. If you still have an error, it could be that you are deleting objects on some other place so the List is containing invalid pointers. But without full code is hard to say what is happening. If the objects are getting deleted on some other place, than you'de need to set List's A*'s to nullptr explicitetly, otherwise if (a) would still evaluate to true.