这是从std::vector中移除元素的有效方法吗?

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无法显示该行),因此我想确保这部分没有问题。还是有问题...?
更新:我找到了错误,实际上是在我的代码的另一个部分。

这对我来说看起来很好,我怀疑你的问题在其他地方,只是在这里显示出来了。 - jcoder
如果 shouldRemove 评估为 true,则 while 循环是一个无限循环。 - billz
1
它取决于最后一个元素的值,这是一个无限循环。 - billz
1
我喜欢这个结构!如果向量中的粒子顺序无关紧要,那么这似乎是处理这样一个CPU密集型循环最有效的方法。 - Dan Nissenbaum
иҝҷйҮҢзҡ„з»“жһ„еҸҜиғҪжҜ”дёҖдәӣзӯ”жЎҲдёӯжҸҗеҲ°зҡ„remove_if()жӣҙеҝ« - еӣ дёәremove_if()дҝқжҢҒеү©дҪҷе…ғзҙ зҡ„йЎәеәҸпјҢиҖҢиҝҷдёӘз»“жһ„дёҚдҝқжҢҒйЎәеәҸгҖӮ - Dan Nissenbaum
显示剩余3条评论
4个回答

3

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


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

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本身就像你所描述的那样,将旧成员移动到向量的后面,并返回一个指向第一个非有效成员的迭代器。将此迭代器和向量的end()传递给erase,允许erase删除所有旧成员,因为它们在一个连续的块中。在您的情况下,在调用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());

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

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接