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

时间:2022-12-30 17:01:13

I have a vector that stores pointers to many objects instantiated dynamically, and I'm trying to iterate through the vector and remove certain elements (remove from vector and destroy object), but I'm having trouble. Here's what it looks like:

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

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

When any of the Entity objects get to xPos>1.5, the program crashes with an assertion error...Anyone know what I'm doing wrong?

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

I'm using VC++ 2008.

我正在使用VC ++ 2008。

5 个解决方案

#1


You need to be careful because erase() will invalidate existing iterators. However, ir returns a new valid iterator you can use:

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

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

#2


The "right" way to do this is using an algorithm:

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

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

Now I know what you're thinking. You're thinking that some of the other answers are shorter.But, (1) this method typically compiles to faster code -- try comparing it, (2) this is the "proper" STL way, (3) there's less of a chance for silly errors, and (4) it's easier to read once you can read STL code. It's well worth learning STL programming, and I suggest you check Scott Meyer's great book "Effective STL" which has loads of STL tips on this kind of stuff.

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

Another important point is that by not erasing elements until the end of the operation, the elements don't need to be shuffled around. GMan was suggesting to use a list to avoid this, but using this method, the entire operation is O(n). Neil's code above, in contrast, is O(n^2), since the search is O(n) and removal is O(n).

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

#3


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

#4


Once you modify the vector, all outstanding iterators become invalid. In other words, you can't modify the vector while you are iterating through it. Think about what that does to the memory and you'll see why. I suspect that your assert is an "invalid iterator" assert.

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

std::vector::erase() returns an iterator that you should use to replace the one you were using. See here.

std :: vector :: erase()返回一个迭代器,您应该用它来替换您正在使用的迭代器。看这里。

#5


The main problem is that most stl container iterators do not support adding or removing elements to the container. Some will invalidate all iterators, some will only invalidate an iterator that is pointing at an item that is removed. Until you get a better feeling for how each of the containers work, you will have to be careful to read the documentation on what you can and can't do to a container.

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

stl containers don't enforce a particular implementation, but a vector is usually implemented by an array under the hood. If you remove an element at the beginning, all the other items are moved. If you had an iterator pointing to one of the other items it might now be pointing at the element after the old element. If you add an item, the array may need to be resized, so a new array is made, the old stuff copied over, and now your iterator is pointing to the old version of the vector, which is bad.

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

For your problem it should be safe to iterate through the vector backwards and remove elements as you go. It will also be slightly faster, since you wont be moving around items that you are going to later delete.

对于您的问题,向后迭代向量并随时删除元素应该是安全的。它也会稍微快一点,因为你不会移动你将要删除的项目。

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

#1


You need to be careful because erase() will invalidate existing iterators. However, ir returns a new valid iterator you can use:

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

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

#2


The "right" way to do this is using an algorithm:

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

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

Now I know what you're thinking. You're thinking that some of the other answers are shorter.But, (1) this method typically compiles to faster code -- try comparing it, (2) this is the "proper" STL way, (3) there's less of a chance for silly errors, and (4) it's easier to read once you can read STL code. It's well worth learning STL programming, and I suggest you check Scott Meyer's great book "Effective STL" which has loads of STL tips on this kind of stuff.

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

Another important point is that by not erasing elements until the end of the operation, the elements don't need to be shuffled around. GMan was suggesting to use a list to avoid this, but using this method, the entire operation is O(n). Neil's code above, in contrast, is O(n^2), since the search is O(n) and removal is O(n).

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

#3


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

#4


Once you modify the vector, all outstanding iterators become invalid. In other words, you can't modify the vector while you are iterating through it. Think about what that does to the memory and you'll see why. I suspect that your assert is an "invalid iterator" assert.

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

std::vector::erase() returns an iterator that you should use to replace the one you were using. See here.

std :: vector :: erase()返回一个迭代器,您应该用它来替换您正在使用的迭代器。看这里。

#5


The main problem is that most stl container iterators do not support adding or removing elements to the container. Some will invalidate all iterators, some will only invalidate an iterator that is pointing at an item that is removed. Until you get a better feeling for how each of the containers work, you will have to be careful to read the documentation on what you can and can't do to a container.

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

stl containers don't enforce a particular implementation, but a vector is usually implemented by an array under the hood. If you remove an element at the beginning, all the other items are moved. If you had an iterator pointing to one of the other items it might now be pointing at the element after the old element. If you add an item, the array may need to be resized, so a new array is made, the old stuff copied over, and now your iterator is pointing to the old version of the vector, which is bad.

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

For your problem it should be safe to iterate through the vector backwards and remove elements as you go. It will also be slightly faster, since you wont be moving around items that you are going to later delete.

对于您的问题,向后迭代向量并随时删除元素应该是安全的。它也会稍微快一点,因为你不会移动你将要删除的项目。

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