4

以下のコードのように、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);
}

私のスプライトクラスにはデストラクタがありませんでした...

もう1つの情報は、デバッグ中に、内部関数の消去でクラッシュすることがわかりました: _Destroy(_Mylast - 1, _Mylast);


問題は解決しました!その理由は私の Sprite クラスにあります。それをスマート ポインターとしてラップし、そのメンバー変数として別のスマート ポインターを作成しました。今はスマート ポインター メンバー変数を使用しませんでしたし、システムは再びクラッシュしませんでした....ベクターからスプライトを消去するときに、そのクラス内でスマート ポインターを使用できない理由について引き続き考えます。それは彼のメンバー変数で重要ですか?スマート ポインターを訴える代わりに生のポインターのみを使用する場合、そのメンバー変数を削除する必要がありますか?

4

4 に答える 4

6

消去しようとしている反復子がベクトルの開始反復子である場合、これ。

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

それでもクラッシュが発生する場合は、スプライト クラスに何か問題があるはずです。

于 2012-11-19T22:41:25.933 に答える
3

erase-removeイディオムを試してみます。

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
于 2012-11-19T23:50:37.773 に答える
3

If siSprite == m_vSprites.begin()thensiSprite-1は合法ではありません。この種のループを記述する通常の方法は、

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

エラーはまったく無関係なものである可能性があるため、これが実際に問題を解決するかどうかはわかりません。

于 2012-11-19T22:40:53.270 に答える
1

消去すると新しい割り当てが発生する可能性があり、イテレータはそこで中断する可能性があります。このようにすることをお勧めします:

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クラスのデストラクタ内にある必要があります。

于 2012-11-19T23:00:30.443 に答える