这是从 std::vector 中删除项目的有效方法吗?

Is this a valid way of removing items from of std::vector?

本文关键字:有效 方法 删除项目 std vector      更新时间:2023-10-16

这是我的代码,用于更新向量中的项目列表并删除其中一些:

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无法向我显示线路),所以我想确保这部分没问题。还是...?

更新:我发现了这个错误,它确实在我的代码的另一部分。

是的,这是一种有效的方法。但是,如果它不是程序中的性能瓶颈,那么最好使用智能指针来管理Particle对象的生存期。

看看 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() );

您正在迭代 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;
    }
}

或者,更好的是,使用智能指针和擦除/删除成语。Remove_if本身按照您的描述执行,将旧成员移动到向量的后面,并返回指向第一个无效成员的迭代器。传递此内容和向量对eraseend()允许擦除所有旧成员,因为它们位于连续块中。在您的方案中,您必须在调用 erase 之前删除每个:

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());

然后测试整个代码的性能,并在实际瓶颈所在的地方进行优化。

我在代码中没有看到任何直接问题。您可能在向量内的实际指针方面遇到了一些问题。

尝试在代码上运行 valgrind 以检测任何隐藏的内存访问问题,或切换到智能指针。