4

ベクター内のアイテムのリストを更新し、それらの一部を削除するための私のコードは次のとおりです。

std::vector<Particle*> particles;

...

int i = 0;
while ( i < particles.size() ) {
    bool shouldRemove = particles[ i ]->update();
    if ( shouldRemove ) {
        delete particles[ i ];
        particles[ i ] = particles.back();
        particles.pop_back();
    } else {
        i++;
    }
}

削除する必要があるアイテムを見つけたら、それをベクターの最後のアイテムに置き換えて、バッキング配列の残りの部分を複数回コピーする可能性を回避します。はい、私はそれが時期尚早の最適化であることを知っています...

これはベクターからアイテムを削除する有効な方法ですか? この辺りのどこかでときどき (!) クラッシュが発生しますが、正確に追跡することはできません (LLDB は行を表示しません)。そのため、この部分が問題ないことを確認したいと思います。またはそれは... ?

更新: バグを見つけましたが、実際にはコードの別の部分にありました。

4

4 に答える 4

3

はい、これは有効な方法です。ただし、それがプログラムのパフォーマンスのボトルネックでない場合は、スマート ポインターを使用してParticleオブジェクトの有効期間を管理することをお勧めします。

于 2012-12-04T10:30:24.223 に答える
1

std::remove_ifを見てください。

また、生活を楽にするかもしれないので、共有ポインタを使用するのが良いかもしれません:-)

typedef std::shared_ptr< Particle > ParticlePtr;

auto newend = std::remove_if( particles.begin(), particles.end(), [](ParticlePtr p) {return p->update();} );
particles.erase( newend, particles.end() );
于 2012-12-04T10:37:05.860 に答える
1

あなたはSTLベクトルを繰り返し処理しているので、イテレータを使用してください。それが目的です。

std::vector<Particle*>::iterator particle = particles.begin();
while ( particle != particles.end() ) {
    bool shouldRemove = particle->update();
    if ( shouldRemove ) {
        particle = particles.remove(particle); //remove returns the new next particle
    } else {
        ++particle;
    }
}

または、さらに良いことに、スマート ポインターとerase/remove idiomを使用します。Remove_if 自体は、古いメンバーをベクトルの後ろに移動し、最初の無効なメンバーを指すイテレータを返します。this と vectorend()を to に渡すと、 eraseerase は隣接するブロックにあるすべての古いメンバーを消去できます。あなたのシナリオでは、消去を呼び出す前にそれぞれを削除する必要があります。

auto deleteBegin = std::remove_if(
  particles.begin(), particles.end(),
  [](Particle* part){ return part->update();}));
for(auto deleteIt = deleteBegin; deleteIt != particles.end(); ++deleteIt)
    delete *deleteIt;
std::erase(deleteBegin, particles.end());

または C++11 より前:

bool ShouldDelete(Particle* part) {
     return part->update();
}

typedef vector<Particle*> ParticlesPtrVec;

ParticlesPtrVec::iterator deleteBegin = std::remove_if(
    particles.begin(), particles.end(), ShouldDelete);
for(ParticlesPtrVec::iterator deleteIt = deleteBegin; 
         deleteIt != particles.end(); ++deleteIt)
    delete *deleteIt;
std::erase(deleteBegin, particles.end());

次に、コード全体のパフォーマンスをテストし、実際のボトルネックがどこにあるかを最適化します。

于 2012-12-04T11:04:08.473 に答える
0

コードに直接的な問題は見られません。ベクトル内の実際のポインターに問題がある可能性があります。

コードで valgrind を実行して、隠れたメモリ アクセスの問題を検出するか、スマート ポインターに切り替えてみてください。

于 2012-12-04T10:24:18.333 に答える