容器遍歷是日常開發高頻操作。C++ 提供 for_each 算法、仿函式、Lambda 運算式、範圍 for(C++11)多種方式。本文系統對比 Java Iterator、C# foreach、C++ 三代遍歷演進,深度解析 for_each + 仿函式/Lambda 實戰模式、範圍 for 優勢、平行算法整合,建立現代遍歷最佳實踐。
| 語言 | 經典方式 | 現代語法 | 型別安全 |
|---|---|---|---|
| Java | Iterator + hasNext/next | for (Item item : list) (JDK 5) | 泛型編譯期檢查 |
| C# | IEnumerator + MoveNext/Current | foreach (var item in list) | 泛型編譯期檢查 (C# 2.0) |
| C++ | for_each(begin, end, func) | for (auto& item : container) (C++11) | 模板實例化檢查 |
template <class T>
class AddValue {
T theValue;
public:
AddValue(const T& v) : theValue(v) {}
void operator()(T& elem) const { elem += theValue; }
};
vector<int> v = {1,2,3,4,5};
for_each(v.begin(), v.end(), AddValue<int>(10)); // 每元素 +10
缺點:需定義類別、重載 operator()、樣板參數冗長。
int total = 0;
for_each(v.begin(), v.end(), [&total](int x) { total += x; });
// 無捕獲
for_each(v.begin(), v.end(), [](int x) { cout << x << ' '; });
// 混合捕獲
bool display = true;
for_each(v.begin(), v.end(), [&total, display](int x) {
total += x;
if (display) cout << x << endl;
});
優勢:就地定義、捕獲區域變數、無類別開銷。
for (auto& x : v) x += 10; // 修改元素
for (const auto& x : v) cout << x; // 唯讀
for (auto x : v) { ... } // 複本(避免修改原容器)
優勢:語法最簡潔、編譯器展開為迭代器版本、支援陣列/初始化列表/自定義類型(需 begin/end)。
#include
#include
for_each(execution::par, v.begin(), v.end(),
[](int& x) { x *= 2; }); // 平行執行,需線程安全操作
// 或使用 transform_reduce 等平行算法
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 簡單修改/唯讀遍歷 | 範圍 for | 語法最清晰、零開銷 |
| 需捕獲區域狀態/複雜邏輯 | for_each + Lambda | 捕獲靈活、就地定義 |
| 函式式風格/可組合管線 | views + ranges (C++20) | 惰性評估、管線組合 |
| 大數據/計算密集 | 平行算法 | 多核加速、自動排程 |
| 舊代碼維護 | for_each + 仿函式 | 相容性、無 Lambda 支援環境 |