Как предотвратить возникновение ошибки сегментации, когда объект в векторе стирается в цикле for? - PullRequest
3 голосов
/ 07 января 2012

[РЕДАКТИРОВАТЬ 2] Это, вероятно, потому, что поверхность освобождается, когда она все еще используется другими объектами ... Поэтому я хочу написать ее, чтобы она освобождалась, только если на экране больше нет объекта.

[РЕДАКТИРОВАТЬ] [ОБНОВЛЕНИЕ] Я исправил код для использования итератора, и у меня все еще была та же проблема ... Я только что подтвердил, что это проблема с деструктором объекта. В классе деструктор вызывает SDL_FreeSurface (image); освободить изображение объекта из памяти ... Но объекты, созданные с помощью конструктора копирования, явно не в порядке с этим. Что мне нужно сделать, чтобы он правильно работал с объектами, созданными с помощью конструктора копирования? Я не могу найти что-либо в Google, относящееся к этому.

Число относится к количеству пуль на экране в данный момент ... У меня есть вектор объекта "пуля" (vector bullet;) ... Код проверяет, нажата ли кнопка триггера (z) и добавляет новый маркер в вектор, если он есть. Затем он обновляется (перемещается, мигает), затем проверяет, находится ли пуля в конце экрана ... Все работает правильно, пока пуля не достигнет конца экрана, где она должна быть уничтожена.

if (trigger)
{
  bullet.push_back(Bullet(position.x, position.y));
  ++number;
}

for(int i = 0; i < bullet.size(); i++)
{
  bullet[i].update();
}

Ниже описана проблема ... Когда объект маркера стирается, программа завершает работу с ошибкой сегментации ... Теперь я понимаю, почему это происходит, поскольку размер вектора изменяется, пока он находится в цикле, но Я не могу понять, как это исправить ... Я добавил перерыв, думая, что это решит проблему, поскольку только одна пуля может быть <= 0 в любой момент времени, но это не так ... У меня изначально было оператор if в последнем цикле for после функции update, но я поместил его в собственный цикл for, чтобы можно было использовать разрыв. </p>

for(int i = 0; i < bullet.size(); i++)  
{
  if (bullet[i].position.y <= 0)
  {     
    bullet.erase(bullet.begin() + i);
    --number;
    break;
  }
}

Я новичок в векторах, поэтому, пожалуйста, потерпите меня здесь, если я чего-то не понимаю или я делаю ошибку n00b.

1 Ответ

11 голосов
/ 07 января 2012

Стандартный цикл стирания для контейнеров последовательности выглядит следующим образом:

for (std::vector<Bullet>::iterator it = v.begin(); it != v.end() /* not hoisted */; /* no increment */)
{
    if (delete_condition)
    {
        it = v.erase(it);
    }
    else
    {
        ++it;
    }
}

Использование итераторов предпочтительнее, чем использование счетного индекса, поскольку он освобождает ваш код от встречной арифметики, которая ничего не добавляет к ясности кода и представляет собой довольно большую неприятность, в то время как представленная здесь версия итератора является довольно самостоятельной. -explanatory.

Ключ не должен увеличивать переменную цикла в случае erase.

Вы также можете посмотреть на remove/erase идиому:

v.erase(std::remove_if(v.begin(), v.end(),
                       [](Bullet & b) -> bool { return delete_condition }),
        v.end());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...