引言
用常規方法遍歷QMap,刪除滿足條件元素時出現“讀取位置0xXXX時發生訪問沖突”。查看“調用堆棧”指向QMap<int,int>::iterator::operator++()
和QMapNode<int,int>::nextNode()
定位為刪除iterator中元素引起iterator的遍歷異常,特記錄如下:
常規錯誤遍歷QMap方法
QMap<int,int>::iterator iter; //遍歷map for (iter = TimerMap_T1_I->begin(); iter != TimerMap_T1_I->end(); iter++) { if (tempNR>=iter.key())//如果鍵值對中發送序號小於或等於該tempNR對應的T1計時器復位,並移出鍵值對 { killTimer(iter.value()); TimerMap_T1_I->erase(iter); } }
錯誤在於: iter指針在元素被刪除后失效了,回到for語句中與 TimerMap_T1_I->end()
進行比較時發生錯誤
改進后遍歷QMap方法
QMap<int,int>::iterator iter; //遍歷map for (iter = TimerMap_T1_I->begin(); iter != TimerMap_T1_I->end(); ) { if (tempNR>=iter.key())//如果鍵值對中發送序號小於或等於該tempNR對應的T1計時器復位,並移出鍵值對 { killTimer(iter.value()); TimerMap_T1_I->erase(iter++); //滿足刪除條件,刪除當前結點,並指向下面一個結點 } else { iter++;//條件不滿足,指向下面一個結點 } }
TimerMap_T1_I->erase(iter++)
中map中在刪除iter的時候,先將iter做緩存為iter1,然后執行iter++使之指向下一個結點,再進入erase函數體中執行刪除操作,刪除時使用的iter其實是緩存下來的iter1(也就是當前iter(做了加操作之后的iter)所指向結點的上一個結點)。
這和TimerMap_T1_I->erase(iter); iter++;
這種執行序列是不相同的。前者在erase執行前進行了加操作,在iter被刪除(失效)前進行了加操作,是安全的;后者是在erase執行后才進行加操作,而此時iter已經被刪除(當前的迭代器已經失效了),對一個已經失效的迭代器進行加操作,行為是不可預期的,這種寫法勢必會導致 map操作的失敗並引起進程的異常。
總結
參考
stl map高效遍歷刪除的方法
在遍歷中使用 iterator/reverse_iterator 進行 Erase 的用法
轉自:https://blog.csdn.net/lm409/article/details/69257827
注意:
iterator QMap::end ()