迭代存取的謬誤

昨天寫的兩段愚蠢的Code,可以掉入兩個這樣的陷阱,刀也該拿去再磨磨了。

第一個

#include <vector>

using namespace std;

int main()
{
vector<int> v;

// .... 寫了某些code 有可能有資料存到v裡頭 ....

for (unsigned int i=v.size()-1 ; i>=0 ; --i)
v.pop_back();

return 0;
}


第二個

#include <list>

using namespace std;

int main()
{
list<int> l;
for (int i=0 ; i<10 ; ++i)
l.push_back(i);

// 移除裡面的元素
for (int i=0 ; i<l.size() ; ++i)
l.remove(i);

return 0;
}


第一個程式執行結果理應是無限迴圈,肇因於我在宣告i時使用了unsigned int作為資料型態,而我使用遞減進行for迴圈的迭代,使用unsigned僅僅是想減少warning的出現,沒想到這卻也是敗筆。由於unsinged int 沒有負數,因此當數值為0後,再進行減1的動作會變成最大值(反之,最大值再加1會成為0),因此這個迴圈的條件恆成立。若你認為只有for的條件判斷有問題需要修改,那你就錯了!在for的初始化部份也存在問題,當v.size()為0時,i的起始就因減1而成為最大值,也會造成程式的執行不正確,就算只改了判斷式,程式依然有可能進行錯誤的迭代。

第二個程式則是還沒移除所有的元素就會結束。因為l.size()是即時反應這個list中的元素個數,而我們使用l.remove()後會使l.size()減少,但是i依然會增加,導致我們只會移除list內一半數量。比較好的方法應該改為用while迴圈,並以l.empty()當作條件來判斷是否要結束;不過,若是常常使用vector.size()作為迴圈條件,就會覺得這個迴圈很直覺的是對的,難以察覺臭蟲的存在。

留言