2010-11-14 48 views
2

我认为下面的代码可以工作,但是当目标小部件位于矢量的末尾时它会崩溃。从std :: vector连续擦除的安全方法?

for(std::vector<AguiWidget*>::iterator it = children.begin(); 
     it != children.end(); ++it) 
    { 
     if((*it) == widget) 
      it = children.erase(it); 
    } 

我希望它通过并删除它找到的小部件的任何实例。我明白这个方法是N^2,但是由于这是事件驱动,所以很好。我只是不知道为什么这会失败。当它发生时,'它'==小部件。

感谢

+0

退房http://stackoverflow.com/questions/347441/erasing-elements-from-a-vector – GWW 2010-11-14 02:34:20

回答

7

您可以使用擦除,删除成语来擦除等于widget所有元素。

children.erase(remove(children.begin(), children.end(), widget), children.end()); 
2

如果您想使用那样的擦除,您应该坚持列表。但问题是你无效你的迭代器,然后尝试增加它。试试这个。

for(std::vector<AguiWidget*>::iterator it = children.begin(); 
    it != children.end();) 
{ 
    if(*it == widget) 
     children.erase(it++); 
    else 
     ++it; 
} 

请注意,我没有递增for-loop语句中的迭代器。

+1

这是关键原因原件()循环失败。在重新测试循环终止条件之前,它总是递增迭代器。将循环体中的迭代器更改为end(),然后尝试'++ it'将你送入高地。 – Blastfurnace 2010-11-14 02:58:07

+0

这里没有理由使用列表。 – 2010-11-14 11:10:58

+0

@Matthieu:我提到这是由于列表比任务涉及删除内部元素的向量更有效。尽管使用矢量执行此任务完全符合代码合法性,但每次删除都会有很大的代价,因为所有后续项都需要在内存中移动,并且可能涉及大量的复制和内存重新分配。列表不会遇到这个问题,因为他们可以重新排列几个指针来完成同样的事情。 – 2010-11-15 16:45:17

0

你知道你在比较指针,而不是解除引用,对不对?

你能告诉我们,如果你使用remove-erase成语,会发生什么?这将是快速(呃比你的代码)和更正:

children.erase(std::remove_if(children.begin(), children.end(), 
           std::bind1st(std::equal_to<AguiWidget*>(), 
              widget))); 

此外,不要忘记先删除指针。

for_each_if(children.begin(), children.end(), 
      std::bind1st(std::equal_to<AguiWidget*>(), widget), 
      Delete()); 

当然,你必须确保没有两个指针指向同一个对象。

0

要补充Blastfurnace的回答,您也可以使用简单的for循环来做到这一点,如果您反向执行此操作。

for (widgets::reverse_iterator it = children.rbegin(), end = children.rend(); 
    it != end; ++it) 
{ 
    if (*it == widget) { children.erase(it.base()); } 
}