2010-12-21 119 views
5

我收到錯誤與此代碼:矢量迭代器不可取消?

for(std::vector<AguiTimedEvent*>::iterator it = timedEvents.begin(); 
    it != timedEvents.end();) 
{ 
    if((*it)->expired()) 
    { 
     (*it)->timedEventCallback(); 
     delete (*it); 

     it = timedEvents.erase(it); 
    } 
    else 
     it++; 
} 

可能是什麼問題呢?

定時事件有時會推一個新的時,其回調被調用時,可能會做

感謝

+0

什麼是確切的錯誤文本? – Tom 2010-12-21 23:20:51

+0

表達式:向量迭代器不可忽略 (調試斷言失敗) – jmasterx 2010-12-21 23:22:42

+2

`timedEventCallback`或`AguiTimedEvent`的析構函數是否直接或間接修改`timedEvents`? – 2010-12-21 23:28:36

回答

7

如果您正在循環一個向量並且回調函數導致向量被添加到,則所有到向量中的迭代器可能會失效,包括循環變量it

在這種情況下(回調修改向量),您最好使用索引作爲循環變量。

您可能需要對設計進行一些徹底分析,以確保您不會產生任何意外的無限循環。

E.g.

for(std::vector<AguiTimedEvent*>::size_type n = 0; 
    n < timedEvents.size();) 
{ 
    if(timedEvents[n]->expired()) 
    { 
     timedEvents[n]->timedEventCallback(); 
     delete timedEvents[n]; 

     timedEvents.erase(timedEvents.begin() + n); 
    } 
    else 
     n++; 
} 
1

編輯:

定時事件有時會推動在新 一個當它的回調被呼叫時, 可能會這樣做

是的,這是非常絕對不安全。如果矢量必須調整大小,那麼它的所有指針和迭代器都將失效。你永遠不應該插入到一個矢量的中間,而它正在迭代,這將導致死亡。也許如果你轉換爲循環數字,問題就會解決。

3

定時事件有時會推一個新的時,其回調被調用時,可能會做

是。

如果向矢量添加元素,it可能會失效。

1

聽起來像是std::remove_copy_ifstd::remove_if工作:(沒有測試過這一點,但它應該給你的想法...)

#include <algorithm> 
#include <functional> 

//I'm sure you probably already have a delete functor lying around, right? 
// No? Well here's one for you.... 
struct Deleter : public std::unary_function<AguiTimedEvent*, void> 
{ 
    void operator()(AguiTimedEvent* toNuke) 
    { 
     delete toNuke; 
    } 
}; 

std::vector<AguiTimedEvent*> toRun; 
std::remove_copy_if(timedEvents.begin(), timedEvents.end(), 
    std::back_inserter(toRun), std::not1(std::mem_fun(&AguiTimedEvent::expired))); 
timedEvents.erase(std::remove_if(timedEvents.begin(), timedEvents.end(), 
    std::mem_fun(&AguiTimedEvent::expired), timedEvents.end()); 
std::for_each(toRun.begin(), toRun.end(), 
    std::mem_fun(&AguiTimedEvent::timedEventCallback)); 
std::for_each(toRun.begin(), toRun.end(), Deleter()); 

注意,這種解決方案需要線性時間,而你需要四次時間。這也乾淨地擺脫了回調可能添加到新矢量的問題,通過刪除關於該矢量的決定直到已經完成從矢量的移除爲止。另一方面,它檢查expired標誌兩次,所以如果這是一個複雜的操作,這可能會更慢。