小心移除 GList 裡的 Node

最近忙著開發新的 LXNM(Lightweight Network Manager),但在開發的過程中碰到了一個 Critical Bug,該 Bug 會讓 LXNM Daemon Crashes。難過的是,已經費盡心思卻仍然找不出問題所在,以致浪費好多時間在 debug。最後多虧了 Paulliu 的協助,終於找出了程式中臭蟲,令人想不到的是,問題居然是出在 GList 的操作。

這問題出在於移除 GList 裡的 Node 之後,再讀取下一個 Node 時會 Crash,這有一個簡化後的錯誤範例:
GList *node;

for (node=mylist;node;node=g_list_next(node)) {
mylist = g_list_delete_link(mylist, node);
}

這樣表面看起來或許沒有錯誤,但以 Link-list 的基礎觀點來看,卻馬上可以發現到問題所在。該程式中,當迴圈進行到第二輪時,會因為 g_list_next() 無法取得下一個 Node 而死在那裡,因為供參考的 Node 已經在第一輪迴圈就被刪除,我們無法取得其 Node->next,當然就會發生錯誤。因此,需要稍微修改,以避免掉這樣的問題:
GList *node;
GList *next_node;

for (node=mylist;node;node=next_node) {
next_node = g_list_next(node);
mylist = g_list_delete_link(mylist, node);
}

GLib 提供的 API 包裝,讓懶惰的我們可以很輕鬆的建立和操作 Link-list,當然難免就會不小心寫出像這樣有問題的 Code 來。因此,對程式開發者而言,就算 GLib 再方便好用,資料結構和各種演算法的理論還是無法完全拋棄。

這個網誌中的熱門文章

Web 技術中的 Session 是什麼?

NodeJS 與 MongoDB 的邂逅

淺談 USB 通訊架構之定義(一)

淺談 USB 通訊架構之定義(二)

JavaScript 好用的 async 異步函數!