如何擦除&删除指向存储在向量中的对象的指针?

时间:2009-06-13 19:27:59

标签: c++ visual-c++ vector iterator erase

我有一个向量存储指向动态实例化的许多对象的指针,我正在尝试迭代向量并删除某些元素(从向量中移除并销毁对象),但我遇到了麻烦。这是它的样子:

    vector<Entity*> Entities;
    /* Fill vector here */
    vector<Entity*>::iterator it;
    for(it=Entities.begin(); it!=Entities.end(); it++)
        if((*it)->getXPos() > 1.5f)
            Entities.erase(it);

当任何实体对象到达xPos&gt; 1.5时,程序崩溃并出现断言错误... 谁知道我做错了什么?

我正在使用VC ++ 2008。

5 个答案:

答案 0 :(得分:40)

您需要小心,因为erase()将使现有迭代器无效。但是,它将返回一个可以使用的新的有效迭代器:

for ( it = Entities.begin(); it != Entities.end(); ) {
   if( (*it)->getXPos() > 1.5f ) {
      delete * it;  
      it = Entities.erase(it);
   }
   else {
      ++it;
   }
}

答案 1 :(得分:9)

“正确”的方法是使用算法:

#include <algorithm>
#include <functional>

// this is a function object to delete a pointer matching our criteria.
struct entity_deleter
{
    void operator()(Entity*& e) // important to take pointer by reference!
    { 
        if (e->GetXPos() > 1.5f)
        {
            delete e;
            e = NULL;
        }
}

// now, apply entity_deleter to each element, remove the elements that were deleted,
// and erase them from the vector
for_each(Entities.begin(), Entities.end(), entity_deleter());
vector<Entity*>::iterator new_end = remove(Entities.begin(), Entities.end(), static_cast<Entity*>(NULL));
Entities.erase(new_end, Entities.end());

现在我知道你在想什么。你认为其他一些答案更短。 但是,(1)这种方法通常编译为更快的代码 - 尝试比较它,(2)这是“正确的”STL方式,(3)傻错误的机会较少,(4)它更容易阅读一旦你可以阅读STL代码。非常值得学习STL编程,我建议你查看Scott Meyer的伟大着作“Effective STL”,它有很多关于这类东西的STL技巧。

另一个重要的一点是,通过在操作结束之前不擦除元素,不需要对元素进行混洗。 GMan建议使用列表来避免这种情况,但使用这种方法,整个操作都是O(n)。相反,上面的Neil代码是O(n ^ 2),因为搜索是O(n),删除是O(n)。

答案 2 :(得分:2)

if((*it)->getXPos() > 1.5f)
{
   delete *it;
   it = Entities.erase(it);
}

答案 3 :(得分:0)

修改向量后,所有未完成的迭代器都将变为无效。换句话说,在迭代向量时无法修改向量。想想它对记忆的作用,你会明白为什么。我怀疑你的断言是一个“无效的迭代器”断言。

std :: vector :: erase()返回一个迭代器,您应该用它来替换您正在使用的迭代器。请参阅here

答案 4 :(得分:0)

主要问题是大多数stl容器迭代器不支持向容器添加或删除元素。有些会使所有迭代器无效,有些只会使指向被删除项的迭代器无效。在您对每个容器的工作方式有了更好的了解之前,您必须小心阅读有关容器能够做什么和不能做什么的文档。

stl容器不强制执行特定的实现,但是向量通常由引擎盖下的数组实现。如果在开头删除元素,则移动所有其他项。如果你有一个指向其他项的迭代器,它现在可能指向旧元素之后的元素。如果你添加一个项目,那么可能需要调整数组的大小,这样就会创建一个新的数组,复制旧的东西,现在你的迭代器指向了旧版本的vector,这很糟糕。

对于您的问题,可以安全地向后遍历向量 并随时删除元素。它也会稍微快一些,因为你不会移动你稍后要删除的项目。

vector<Entity*> Entities;
/* Fill vector here */
vector<Entity*>::iterator it;
for(it=Entities.end(); it!=Entities.begin(); ){
  --it;
  if(*(*it) > 1.5f){
   delete *it;
   it=Entities.erase(it);
  }
}