Ошибка BAD ACCESS при доступе к методу векторного элемента из сенсорного обратного вызова - PullRequest
2 голосов
/ 09 мая 2019

У меня есть структура классов следующим образом:

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

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

и Я предоставил реализацию функции B в соответствующем файле .cpp.

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

Теперь, когда я пытаюсь получить доступ к функции B из другого файла следующим образом:

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);
};

В 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
        }
    }
}

Вызов func () (точнее, доступ к объектутип B) работает нормально, если я вызываю его из метода в XYZ, но вылетает с ошибкой BAD_ACCESS, если я вызываю его из метода touchEndCallback.

Когда я проверял _List в режиме отладки в функции func2 () , он правильно показал, что _List имел пять членов типа B , но когда я проверил список в методе touchEndCallback , он показал, что _List имеет пять членов типа A .

Почему происходит сбой и как его исправить?

1 Ответ

2 голосов
/ 09 мая 2019

Разыщите итератор, чтобы получить указатель A *.Цикл должен выглядеть следующим образом:

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

или вы можете использовать диапазон для:

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

РЕДАКТИРОВАТЬ: Использование необработанных указателей также плохая идея.рассмотрим unique_ptr или shared_ptr .Если у вас все еще есть ошибка, возможно, вы удаляете объекты в каком-то другом месте, поэтому в списке содержатся недопустимые указатели.Но без полного кода сложно сказать, что происходит.Если объекты удаляются в каком-то другом месте, чем вам нужно явно установить для A * Списка значение nullptr, в противном случае, если (a) все равно будет иметь значение true.

...