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

C++ 如何删除&;删除指向存储在向量中的对象的指针?,c++,visual-c++,vector,iterator,erase,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)->

我有一个向量,它存储指向动态实例化的许多对象的指针,我试图遍历该向量并删除某些元素(从向量中删除并销毁对象),但我遇到了麻烦。下面是它的样子:

    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);
矢量实体;
/*这里是填充向量*/
向量::迭代器;
for(it=Entities.begin();it!=Entities.end();it++)
如果((*it)->getXPos()>1.5f)
实体。删除(它);
当任何实体对象到达xPos>1.5时,程序崩溃并出现断言错误。。。 有人知道我做错了什么吗


我正在使用VC++2008。

一旦修改向量,所有未完成的迭代器都将无效。换句话说,在遍历向量时不能修改它。想想这对记忆有什么影响,你就会明白为什么。我怀疑您的断言是“无效迭代器”断言


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

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

for ( it = Entities.begin(); it != Entities.end(); ) {
   if( (*it)->getXPos() > 1.5f ) {
      delete * it;  
      it = Entities.erase(it);
   }
   else {
      ++it;
   }
}
“正确”的方法是使用算法:

#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());
#包括
#包括
//这是一个函数对象,用于删除符合条件的指针。
结构实体删除器
{
void运算符()(实体*&e)//通过引用获取指针很重要!
{ 
如果(e->GetXPos()>1.5f)
{
删除e;
e=零;
}
}
//现在,将实体_deleter应用于每个元素,删除已删除的元素,
//并从向量中删除它们
对于每个(Entities.begin()、Entities.end()、entity_deleter());
向量::迭代器new_end=remove(Entities.begin(),Entities.end(),static_cast(NULL));
Entities.erase(新建_end,Entities.end());
现在我知道你在想什么了。你在想其他的一些答案比较短。 但是,(1)这种方法通常能编译出更快的代码——试着比较一下,(2)这是“正确的”STL方法,(3)发生愚蠢错误的可能性更小,(4)一旦你能阅读STL代码,阅读起来就更容易了。学习STL编程是很值得的,我建议你看看Scott Meyer的名著《有效的STL》在这类东西上有很多STL提示


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

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

stl容器不强制执行特定的实现,但向量通常由引擎盖下的数组实现。如果在开始时删除元素,则所有其他项都将移动。如果有一个迭代器指向其他项之一,则它现在可能指向旧元素后的元素。如果添加项,则ray可能需要调整大小,因此创建一个新数组,复制旧的内容,现在迭代器指向向量的旧版本,这很糟糕

对于您的问题,应该可以安全地向后迭代向量,并在执行过程中删除元素。这也会稍微快一点,因为您不会在稍后要删除的项目周围移动

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);
  }
}
矢量实体;
/*这里是填充向量*/
向量::迭代器;
for(it=Entities.end();it!=Entities.begin();){
--它;
如果(*(*it)>1.5f){
删除*它;
它=实体。擦除(它);
}
}

请用您使用的语言/环境标记您的问题,以便我们从主页了解您使用的内容(您将获得更多视图)。但你不知道他在代码的其余部分中对向量做了什么!一般来说,向量应该是首选容器,其他条件相同。一般来说,你应该更喜欢STL算法而不是手工编写的循环。我同意这种特定情况需要一个列表,但不知道还需要使用什么这个循环,现在很难推荐移动到列表。我建议的STL算法代码是O(n)。显式循环+列表也是O(n)但是,你放弃了引用和随机访问的地方,这是一个大问题,我建议尽量避免它。我不同意算法不太清楚。它包含一个简单的函子和三个步骤。如果程序员知道如何使用,并且每个C++程序员都应该使用,那么它很容易阅读。e不是简单的“remove(Element)”方法,而是我们必须在任何地方调用这个愚蠢的begin()和end()?这是不正确的,因为从erase()返回的迭代器在erase()之后会递增。我看不到任何循环似乎起作用,尽管我想知道这与Keand64的答案有什么区别?vector::erase()声明调用对象的析构函数,“delete*it;”必要?指针没有析构函数。只有当向量中的东西是实体值的集合时,才会调用它的析构函数。因此,如果您希望避免内存泄漏,则调用delete是必要的。@Gman我想您的意思是引用迭代器,而不是指针。为什么不通过索引向后迭代呢?请实际删除仅使指向已擦除项和之后元素的迭代器失效,而指向较低元素的迭代器不会失效。我没有这样做,并写道顶部的代码是指针是否不需要被删除
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);
  }
}