2009-02-03 84 views

回答

21

如果通過插入或刪除容器成員更改容器,忘記迭代器常常失效。

有關使用STL許多偉大的祕訣我高度建議斯科特邁爾斯的書「有效STL」(sanitised Amazon link

+2

我一般都認同,但是有可能將您的陳述解釋爲「迭代器總是*通過插入或刪除而失效」。向量迭代器永遠不會因刪除* later *元素而失效,既不插入也不刪除其他元素使列表,集合和映射迭代器無效。 – 2009-02-03 12:48:46

+0

@j_random_hacker:這是真的,我會編輯我的迴應 – 2009-02-03 13:32:34

+0

如果可能的話,添加一些代碼 – yesraaj 2009-02-03 13:35:17

8

後遞增,當預遞增會做。

+0

我不能說這是一件大事,因爲它不會損害代碼的正確性,當然一個體面的優化編譯器會生成相同的代碼i ++的原始增量值未使用? (請注意,爲了以防萬一,我總是預加重)FTR:我沒有-1你(沒有+1你)。 – 2009-02-03 13:01:09

+0

@j_random_hacker,完全同意這不是一個大問題,但它是一個常見的STL迭代器習語。這個問題沒有具體說明他所關心的具體類型問題。 – 2009-02-03 15:04:50

+4

根據迭代器的實際情況,編譯器不一定會生成相同的代碼。我++會生成一個臨時值,它不能總是被優化掉。 ++我只是做增量。 – 2009-02-03 22:10:14

9

結束範圍檢查應該使用!=而不是<,因爲指針的順序不能保證。

例子:

for(it = list.begin(); it != list.end(); ++it) 
{ 
    // do stuff 
} 
+0

哎唷!您的C++標準庫實現必須使用原始指針類型的(typedefs)作爲迭代器 - 正是由於這個原因,將所有迭代器實現爲包含指針的不同類型以及合適的運算符重載要安全得多(例如,對於運算符==()但不是運算符<())。 – 2009-02-03 12:53:57

6

使用它們而不斯科特邁爾斯閱讀 「有效STL」 一書。 :)真的。這使得大部分愚蠢的錯誤消失。

7

幾個人:

  • 轉換一個逆向迭代一個基本的迭代器,無需記住迭代器現在將超越它指向一個一個元素。

  • 試圖使用需要隨機訪問迭代器的算法,並使用像集和映射之類的迭代器。

  • 編輯與非const迭代器映射條目的鍵(出現這種情況的基礎上VS.Net,但不會與GCC)erase()

6

正確的延續。

假設:

Container::iterator i = cont.begin(), iEnd = cont.end(); 

上。例如std::map,這不是一個好主意:

for (; i != iEnd; ++i) { 
    if (i->second.eraseCondition()) { 
     cont.erase(i); 
    } 
} 

這會工作:

for (; i != iEnd;) { 
    Container::iterator temp = i; 
    ++temp; 
    if (i->second.eraseCondition()) { 
     cont.erase(i); 
    } 
    i = temp; 
} 

,這也:

for (; i != iEnd;) { 
    if (i->second.eraseCondition()) { 
     cont.erase(i++); 
    } 
    else { 
     ++i; 
    } 
} 

它已經太多次真的,我已經有一些生產代碼:(

3

應用這些修補程序使用一個auto_ptr的容器,例如內

list<auto_ptr<int> > foo; 

幸運的是,現在很多auto_ptr的實現都是爲了使這不可能。

2

這不僅是STL容器的問題 - 在迭代容器時調試容器幾乎總是會導致問題。

這是遊戲中錯誤的常見來源 - 大多數遊戲循環包括迭代每個遊戲對象做某事。如果這個東西添加或刪除了遊戲對象容器中的元素,那麼幾乎肯定會出現錯誤。

解決方案 - 在遊戲代碼中有兩個容器 - objectsToDelete和objectsToAdd - 將對象添加到該容器,並且只有在迭代後才更新遊戲對象容器。

objetsToAdd可以設置,以確保我們不會刪除任何不止一次。

如果您可以在不將對象添加到遊戲對象容器的情況下構造對象,或者它可以是其他類(ObjectCreateCommand?),那麼objectsToDelete可以是Queue,如果您的代碼假定Object實例始終在創建後直接添加到遊戲對象容器例如在構造函數中)。

1
list<int> l1, l2; 
// ... 

for_each(l1.begin(), l2.end(), do_it());