迭代器的使用

本文探讨了在C++ STL中使用迭代器从vector容器删除元素时可能遇到的问题,并通过实例演示了错误操作导致的后果。

先看下面的例子:

vector 的元素刪除

話頭從 container 的元素刪除說起。jyhuang 觀察到「如果 vector 或 list
的最後一個元素符合刪除條件,程式會有問題」。他給我這樣一個片段:

template <typename T>
void print_elements(T elem) { cout << elem << " "; }

void (*pfi)(int) = print_elements; //
函式指標,做為 function object
...
int ia[7] = {0,1,2,3,4,5,6};
vector<int> ivec(ia, ia+7);
for_each(ivec.begin(), ivec.end(), pfi); // 0 1 2 3 4 5 6

for (vector<int>::iterator it = ivec.begin(); it != ivec.end(); it++) {
  if (*it % 2) //
把奇數去掉
    ivec.erase(it);
}
for_each(ivec.begin(), ivec.end(), pfi); // 0 2 4 6
正確!



如果把 array 和 vector 的初值改為:

int ia[8] = {0,1,2,3,4,5,6,7};
vector<int> ivec(ia, ia+8);


則上述程式會當掉。


●I don't think so...

我不相信 STL 會有這麼差勁的表現。所以多做了幾次測試如下。

(1) 把 array 和 vector 的初值改為:

int ia[7] = {0,1,2,3,4,5,7};
vector<int> ivec(ia, ia+7);


程式結果為 0 2 4 7。結果不對,但不會當掉。

(2) 把 array 和 vector 的初值改為:

int ia[7] = {0,1,3,5,7,9,7};
vector<int> ivec(ia, ia+7);


程式結果為 0 3 7 7。錯得離譜,但不會當掉。

(3) 把 array 和 vector 的初值改為:

int ia[7] = {0,2,4,6,0,4,7};
vector<int> ivec(ia, ia+7);


程式執行時會當掉。


我於是多做了一些觀察,然後知道,上述這些動作根本上是完全
不對的。第一個 sample 之執行結果正確,完全是湊巧。

問題不在「最後一個元素是否符合刪除條件」,而在對 iterator
特性的認識。當我們做了 ivec.erase(it) 動作,vector 便動態
減縮了一個元素(邏輯上,後繼元素向前遞補),而 it 不變。
之後 for 迴圈的第三部份述句要求 it++,造成 it 跳過了一個元素...。

看實例:

(1) 初值為 {0,1,2,3,4,5,6}

第一次迭代,發現是偶數: ★ 以下以 e 表示 end()
0 1 2 3 4 5 6 e
^

第二次迭代,發現是奇數:
0 1 2 3 4 5 6 e
  ^

於是將  '1'  刪除,vector 變成:
0 2 3 4 5 6 e
  ^

第三次迭代,發現是奇數(這時已發生錯誤,因為 '2' 被跳過,沒有檢查):
0 2 3 4 5 6 e
    ^

於是將 '3' 刪除,vector 變成:
0 2 4 5 6 e
    ^

第四次迭代,發現是奇數(這時已發生錯誤,因為 '4' 被跳過,沒有檢查):
0 2 4 5 6 e
      ^

於是將 '5' 刪除,vector 變成:
0 2 4 6 e
      ^

第五次迭代,發現 it == vec.end(),於是跳離迴圈:
0 2 4 6 e
        ^

此時 vector 剩餘 0 2 4 6,陰錯陽差地與正確結果吻合。


(2) 初值為 {0,2,4,6,0,4,7}

第一次迭代,發現是偶數: ★ 以下以 e 表示 end()
0 2 4 6 0 4 7 e
^

第二次迭代,發現是偶數:
0 2 4 6 0 4 7 e
  ^

第三次迭代,發現是偶數:
0 2 4 6 0 4 7 e
    ^

第四次迭代,發現是偶數:
0 2 4 6 0 4 7 e
      ^

第五次迭代,發現是偶數:
0 2 4 6 0 4 7 e
        ^

第六次迭代,發現是偶數:
0 2 4 6 0 4 7 e
          ^

第七次迭代,發現是奇數:
0 2 4 6 0 4 7 e
            ^

於是將 '7' 刪除,vector 變成:
0 2 4 6 0 4 e
            ^

第八次迭代,it 越過了 end(),造成越界錯誤。迴圈何時結束,未可知也:
0 2 4 6 0 4 e ? ? ? ? ? ?
              ^


我的結論:

iterator 只適用於在「不更動 container 佈局」的條件下,對 container 做巡訪動作。否則,對 iterator 的取值行為,直觀下極易誤用。

原创网址:http://jjhou.boolan.com/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值