關於STL迭代器失效的思考.

問題:    
    有一個stl容器, 有一個已經獲取到的容器的迭代器, 當向stl容器中新增元素或刪除元素時, 先前拿到的迭代器還有用嗎? 也就是迭代器是否失效了?
   
迭代器失效,有兩個層面的意思,
    1) 無法通過迭代器++,--操作遍歷整個stl容器. 記作: 第一層失效
    2) 無法通過迭代器存取迭代器所指向的內存. 記作: 第二層失效

關於這個問題, 不同的容器對應的結果是不同的. 我們分別分析.

vector
    vector是個連續內存存儲的容器. 如果vector容器的中間某個元素被刪除或從中間插入一個元素. 有可能導致內存空間不夠用而重新分配一塊大的內存.
    這個動作將導致先前獲取的迭代器, 第一層和第二層均失效.

map
    map內部是紅黑樹結構, 當map中新插入或刪除元素後, 樹的結構會相應的調整.
    但是, 通過先前的迭代器, 仍然可以通過++可以遍歷map. 能遍歷到值>當前迭代器的節點. (沒有看具體stl內部實現,初步代碼驗證正確)
    迭代器指向的用戶數據內存始終有效.

list
   同理map, 通過++只能遍歷鏈表右側的節點. 迭代器指向的用戶數據內存也始終有效.

後記:爲什麼會有這篇文章?
   是因爲最近在做一個LRU cache系統, 希望利用stl提供的hash_map和list來實現, 中間涉及到迭代器的是否失效問題.

特別注意,

1) 這裏的結論僅使用於單線程的stl編程. 如果是多線程的, 就不是簡單的迭代器失效問題了, 直接core了. stl是非線程安全的. 
2) 這裏討論的先前獲取的迭代器,一定是沒有被erase的, 如果一旦erase, 那麼迭代器肯定失效. 注意, erase其他迭代器不影響先前獲取的迭代器.

 

map的測試代碼:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <arpa/inet.h>
#include <sstream>
#include <vector>
#include <map>
#include <list>
#include <unistd.h> // for usleep

using namespace std;


#ifndef foreach
#define foreach(container,it) \
            for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)
#endif
int main()
{
    map<int , int> im;

    im[1] = 1;
    im[10] = 10;
    im[20] = 20;
    im[21] = 21;

    map<int, int>::iterator it;
    map<int, int>::iterator it1;
    map<int, int>::iterator it2;
    map<int, int>::iterator it3;

    it1 = im.find(1);
    it2 = im.find(10);
    it3 = im.find(20);

    //--------------------------------
    // 邊遍歷便插入測試
    //--------------------------------
    int i = 30;
    foreach(im,it)
    {
        printf("it->first:%d, it->second:%d\n", it->first, it->second);
        if (i<40)
        {
            im[++i] = i;
            im[-i] = -i;
        }
    }

    printf("-----------------\n");

    //--------------------------------
    // 遍歷完成後,拿着以前的iterator測試
    //--------------------------------
    for(it=it3; it!=im.end(); ++it)
    {
        printf("it->first:%d, it->second:%d\n", it->first, it->second);
    }
    return 0;
}


 

輸出:

it->first:1, it->second:1
it->first:10, it->second:10
it->first:20, it->second:20
it->first:21, it->second:21
it->first:31, it->second:31
it->first:32, it->second:32
it->first:33, it->second:33
it->first:34, it->second:34
it->first:35, it->second:35
it->first:36, it->second:36
it->first:37, it->second:37
it->first:38, it->second:38
it->first:39, it->second:39
it->first:40, it->second:40
-----------------
it->first:20, it->second:20
it->first:21, it->second:21
it->first:31, it->second:31
it->first:32, it->second:32
it->first:33, it->second:33
it->first:34, it->second:34
it->first:35, it->second:35
it->first:36, it->second:36
it->first:37, it->second:37
it->first:38, it->second:38
it->first:39, it->second:39
it->first:40, it->second:40


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章