C ++, как я могу удалить вектор указателей в моей игре

0

Я пытаюсь сделать первую игру симуляром Танкам. Но моя игра падает, когда я пытаюсь удалить вражеский танк (иногда работает, иногда нет), и я не знаю, что не так с моим кодом. Ты мне поможешь?

void Game::update(sf::Time elapsedTime){

if (enemies.size() < 6){

    eTank1 = new EnemyTank(150, 130);
    enemies.push_back(eTank1);
    }

    tank->move(elapsedTime);

for (vector<EnemyTank*>::const_iterator it = enemies.begin(); it != enemies.end();)
{

    if (collision->checkCollisionWithEnemyTankAndTank(tank, *it)){
        (*it)->move(elapsedTime);
    }


    collision->checkShoot(tank->getBulletsVector(), tank, *it); 

    //probably there is a problem
    if ((*it)->getlife() <= 0){

        delete  *it;            
        enemies.erase(it);
        cout << "TANGO DOWN" << endl;
    }
     ++it;
}

checkShoot выглядит так:

void Collision::checkShoot(vector <Bullet*> &bullet, Tank *tank, EnemyTank* enemyTank){

distance = 0;

for (int i = 0; i < bullet.size(); i++){


    distance = abs(bullet[i]->getPosition().x - enemyTank->getPosition().x) + abs(bullet[i]->getPosition().y - enemyTank->getPosition().y);

    if (distance < 45){
        cout << "act life: " << enemyTank->getlife() << endl;
        enemyTank->setLife();       // -0.5 from actual life        
        tank->setVector(i);         // delete bullet from vector        

    }

}

}

И код деструктора

cout << "DESTRU";
delete tank_bullet;

for (auto &it : bullets){ delete it; } bullets.clear();


cout << "DESTRU T - END\n";

Наконец, setVector (i);

void setVector(int index){
     if (!bullets.empty()){
        delete (bullets.at(index));
        bullets.erase(bullets.begin() + index);
    }

}

  • 4
    Вы не можете слепо стереть вектор, по которому вы выполняете итерацию, так как erase приведет к аннулированию итераторов. Однако вас может заинтересовать то, что возвращает функция erase .
  • 1
    Google "стереть-удалить идиому".
Показать ещё 4 комментария
Теги:
pointers
memory-leaks
sfml

1 ответ

0

Ответ действительно в комментариях, но в случае, если они кажутся слишком краткими, я пишу немного более длинное объяснение.

Вот минимальный пример, похожий по стилю на ваш код:

int main() {
  auto v = std::vector<int> {1, 2, 3, 4, 5};
  for(auto it = v.cbegin(); it != v.cend(); ) {
    if(*it == 5)
      v.erase(it);
    ++it;
  }
}

Это segfaults (нет, если вы сравниваете с чем-то, что не является последним элементом vector, например *it == 3, но это поведение, вероятно, зависит от компилятора). Зачем? v.erase(it) аннулирует Итератор it, так что вы не можете использовать it после этой строки. Вместо этого, вы должны использовать то, что erase возвращается, it = v.erase(it), который является итератор после удаленной. Теперь, если это будет v.cend() а на следующей строке вы увеличиваете его, ++it, вы находитесь вне пределов и не повезло.

Я не поощряю вас использовать следующее, но если вы хотите придерживаться стиля своего кода, то что должно работать

if(*it == 5)
  it = v.erase(it);
else
  ++it;

Что else делает, так это то, что он избегает двойного приращения при erase.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню