天天看點

使用纖程簡化枚舉器1:枚舉器的簡單實作

枚舉對象的COM模型的設計,傾向于對消費者(Consumer)友好。對于生産者(Producer)來說,枚舉對象需要被設計為一個狀态機(State Machine),對于複雜的枚舉器,例如樹周遊或複合枚舉,實作起來可能是相當不容易的。

另一方面,生産者的回調模型(被大多數 Win32 函數使用)偏向于對枚舉對象友好。

這一次,消費者需要被構造成一個狀态機,如果消費者對每個回調都做一些複雜的事情,這就需要更多的開發工作。(即使沒有,你也必須建立一個上下文結構來将狀态從調用者通過枚舉器傳遞給回調函數。)

例如,假設我們要編寫一個周遊目錄結構的例程,允許調用者指定在每個決策點要做什麼。 讓我們首先使用回調方式來設計它,代碼如下圖所示:

使用纖程簡化枚舉器1:枚舉器的簡單實作

這裡的設計是調用者調用 EnumDirectoryTree 并提供一個回調函數,該函數被告知找到的每個檔案,并可以決定枚舉應該如何進行。

将其設計為回調可以使得 EnumDirectoryTree 的實作變得更加簡單。

使用纖程簡化枚舉器1:枚舉器的簡單實作

請注意:我沒有試圖讓這個函數變得高效,因為這不是我想表達的主題。 它非常浪費堆棧空間(在周遊一個大型目錄樹時可能會導緻問題)。 這個函數也無法處理比 MAX_PATH 更深的路徑; 解決這個問題超出了本系列的範圍。 我也不擔心重解析點,如果你不謹慎處理它,就可能導緻無限循環。

好吧,上圖的代碼并不難寫。 但那是因為我們讓消費者的生活變得艱難。 消費者需要在每個回調中維護狀态。 例如,假設你想要建構目錄清單及其大小(包括和不包括子目錄)。可能的代碼如下圖所示:

使用纖程簡化枚舉器1:枚舉器的簡單實作
使用纖程簡化枚舉器1:枚舉器的簡單實作
使用纖程簡化枚舉器1:枚舉器的簡單實作
使用纖程簡化枚舉器1:枚舉器的簡單實作

首先,上面的代碼量還不小,更糟的是,程式的整個結構都被狀态管理代碼所掩蓋。 确實很難一眼看出這段代碼試圖做什麼。 相反,你必須盯着 EnumState的代碼,并對正在發生的事情進行逆向工程。

(是的,我可以通過使用内置的堆棧類稍微簡化這段代碼,但正如我在智能指針的文章中所指出的那樣,我嘗試用純C++來呈現這些文章,這樣人們就不會争論哪個類庫最好。)

明天,我們将看看如果函數 EnumDirectoryTree 由調用者而不是枚舉器指定,世界會怎樣!

總結

最後