Как я могу стереть shared_ptr из вектора

Как и приведенные ниже коды, m_vSprites является вектором shred_ptr, если при сбое обновления одного из его элементов я хотел бы удалить его из вектора, но мои коды вылетали, когда я хотел бы использовать стирание. Но не знаю почему, кто-нибудь может помочь?

Причина, по которой мне нужно использовать стирание, заключается в том, что мое приложение будет постоянно добавлять элементы в вектор, но также будет постоянно стирать объекты из вектора, если некоторые элементы удовлетворяют условиям их уничтожения. если бы я не стер это, вектор стал бы огромным, поскольку программа работает!

RECT rcOldSpritePos;
typedef boost::shared_ptr<Sprite> SmartSprite;
vector<SmartSprite>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)
{
// Save the old sprite position in case we need to restore it
rcOldSpritePos = (*siSprite)->getPosition();

if (!((*siSprite)->update()))
{
// Kill the sprite
//siPreviousSprite = siSprite-1;
siSprite = m_vSprites.erase(siSprite);
}
else
{
siSprite++;
// See if the sprite collided with any others
if (checkSpriteCollision(*siSprite))
// Restore the old sprite position
(*siSprite)->setPosition(rcOldSpritePos.left, rcOldSpritePos.top);
}

}

Я изменил коды, как кто-то предложил, но все еще не удалось в функции стирания, пожалуйста, у кого-нибудь есть предложения?

Еще немного информации о том, как добавить элемент в vecotr

Любая проблема здесь?

    SmartSprite sprite;
if (0 < enemies.size())
{
// Pick a random enemy to drop bomb
size_t nRandEnemy = (rand() % enemies.size());
RECT rRandEnemy = enemies.at(nRandEnemy)->getPosition();
sprite.reset(new BombSprite(m_system, rRandEnemy.right-OBJECTSIZE/2,
rRandEnemy.bottom));
m_vSprites.push_back(sprite);
}

В моем классе спрайтов не было деструктора …

еще одна информация, пока я отлаживаю, обнаружил, что
стереть внутреннюю функцию: _Destroy (_Mylast — 1, _Mylast);


проблема решена !, причина в моем классе Sprite, я обертываю его как умный указатель и создал другой умный указатель как его переменную-член. теперь я не использовал переменную-член интеллектуального указателя, и система больше не зависала …. Я буду продолжать думать о том, почему я не могу использовать интеллектуальный указатель внутри этого класса, когда стирает спрайт из вектора, это имеет значение в его переменной члена? мне все еще нужно удалить эту переменную-член, если только использовать необработанный указатель вместо иска смарт-указатель?

4

Решение

Если итератор, который вы собираетесь стереть, является начальным итератором вектора, то this;

siPreviousSprite = siSprite - 1;

Неопределенное поведение. Перестройте ваш цикл следующим образом:

for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); )
{

rcOldSpritePos = (*siSprite)->getPosition();

if (!((*siSprite)->update()))
{
// Kill the sprite
siSprite = m_vSprites.erase(siSprite);
}
else
{
++siSprite;
}
}

Если по-прежнему происходит сбой, значит, что-то не так с вашим классом спрайта.

5

Другие решения

Если siSprite == m_vSprites.begin() затем siSprite-1 не законно Обычный способ написания этого вида цикла

for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); )
{
rcOldSpritePos = (*siSprite)->getPosition();
if ((*siSprite)->update())
{
++siSprite;
}
else
{
siSprite = m_vSprites.erase(siSprite);
}
}

Не уверен, что это действительно решит вашу проблему, потому что ваша ошибка может быть чем-то совершенно не связанным.

3

Я бы попробовал с стереть-удалить идиома.

Вы можете раскрыть bool атрибут из класса спрайт, и проверьте, если это true стереть спрайт из вектора.
Примерно так (код протестирован с VC10 / VS2010 SP1):

#include <algorithm>
#include <iostream>
#include <memory>
#include <ostream>
#include <vector>

using namespace std;struct Sprite
{
explicit Sprite(int spriteId)
: kill(false)
, id(spriteId)
{
}

int id;
bool kill;
};int main()
{
typedef shared_ptr<Sprite> SmartSprite;
typedef vector<SmartSprite> SpriteArray;

SpriteArray sprites;
for (int i = 0; i < 5; i++)
sprites.push_back( make_shared<Sprite>(i*11) );

for (auto it = sprites.begin(); it != sprites.end(); ++it)
cout << (*it)->id << " ";
cout << endl;

sprites[2]->kill = true;
sprites[3]->kill = true;

// Remove sprites with kill flag set
sprites.erase
(
remove_if
(
sprites.begin(),
sprites.end(),
[](const SmartSprite& ps){ return ps->kill; }
),
sprites.end()
);

for (auto it = sprites.begin(); it != sprites.end(); ++it)
cout << (*it)->id << " ";
cout << endl;
}

Выход:

0 11 22 33 44
0 11 44
3

Стирание потенциально приводит к новому распределению, итераторы могут сломаться там. Лучше сделать так:

for(size_t i=0; i<v.size(); ++i)
if(!v[i].update())
{
v.erase(v.begin()+i);
--i; // since the elements shifted up.
}

В противном случае вы можете захотеть вместо этого используйте очереди, Операция стирания очень дорогая для векторов.

РЕДАКТИРОВАТЬ:

Я проверил его с фиктивным классом Sprite и работает нормально, ошибка должна быть в деструкторе класса Sprite.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector