2010-11-14 43 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()); } 
} 
相關問題