闭包遍历vs迭代器:哪种实现更兼顾代码清晰度与性能?
二维矩阵相邻元素遍历方案对比:迭代器 vs 闭包Lambda
我实现了一个二维Matrix类,需要遍历指定元素的相邻元素,目前有两种可行方案:
- 使用迭代器
- 结合lambda表达式的闭包遍历
想咨询这两种方案在性能与可读性方面孰优孰劣,我个人初步认为迭代器的样板代码冗余度较高。
#include <cstddef> #include <functional> #include <iostream> #include <iterator> #include <utility> #include <vector> template <typename T> class Matrix { using array = std::vector<T>; using size = std::size_t; array data; size rows_; size cols_; public: Matrix(size rows, size cols) : data(cols * rows), rows_{rows}, cols_{cols} {} T &operator()(size row, size col) { return data[row * cols_ + col]; } const T &operator()(size row, size col) const { return data[row * cols_ + col]; } int rows() const { return rows_; } int cols() const { return cols_; } void traverse(std::function<void(T &)> f, size row, size col) { for (auto &[rd, cd] : neighbours_delta) { int r = row + rd, c = col + cd; if (r >= 0 && r < rows_ && c >= 0 && c < cols_) f((*this)(r, c)); } } typename array::iterator begin() { return data.begin(); } typename array::iterator end() { return data.end(); } auto neighbours(size row, size col) { return NeighbourIterator(row, col, *this); } protected: std::pair<int, int> neighbours_delta[8] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; struct NeighbourIterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = T; using pointer = T *; using reference = T &; NeighbourIterator(size row, size col, Matrix<T> &m, int neighbour = 0) : row{row}, col{col}, m{m}, neighbour{neighbour} {} auto get_delta() const { return m.neighbours_delta[neighbour]; } bool exists() { auto [rd, cd] = get_delta(); int r = row + rd, c = col + cd; return r >= 0 && r < m.rows_ && c >= 0 && c < m.cols_; } T &get_neighbor() const { auto [rd, cd] = get_delta(); return m(row + rd, col + cd); } reference operator*() const { return get_neighbor(); } pointer operator->() { return get_neighbor(); } NeighbourIterator &operator++() { do { neighbour++; } while (neighbour < 8 && !exists()); return *this; } NeighbourIterator operator++(int) { NeighbourIterator tmp = *this; ++(*this); return tmp; } auto begin() { return NeighbourIterator(row, col, m, 0); } auto end() { return NeighbourIterator(row, col, m, 8); } friend bool operator==(const NeighbourIterator &a, const NeighbourIterator &b) { return a.neighbour == b.neighbour; }; friend bool operator!=(const NeighbourIterator &a, const NeighbourIterator &b) { return a.neighbour != b.neighbour; }; private: Matrix<T> &m; size row, col; int neighbour; }; }; int main() { Matrix<int> m(10, 10); std::fill(m.begin(), m.end(), 0); m.traverse([](int &el) { el = 0; }, 5, 5); for (auto &el : m.neighbours(8, 8)) el = 8; }
性能对比
- 闭包Lambda方案:
traverse函数依赖std::function做类型擦除,会产生微小的间接调用开销,但对于简单逻辑(如示例中的赋值),编译器通常能优化掉大部分开销,日常场景下性能差异可忽略。但如果是高频调用或复杂lambda,类型擦除的损耗会被放大。 - 迭代器方案:自定义迭代器是值类型,所有操作(
operator++、operator*等)都能被编译器完全内联,没有额外间接调用,性能几乎等同于手写原生循环,在极端高频场景下优势明显。
可读性与维护性
- 闭包Lambda方案:代码简洁直观,调用方只需传入处理逻辑的lambda,一眼就能读懂操作意图(如
m.traverse([](int& el) { el = 0; }, 5,5))。但缺点是遍历逻辑被固定在traverse函数中,无法灵活控制遍历过程(比如提前终止、跳过元素)。 - 迭代器方案:确实存在大量样板代码(迭代器关联类型、运算符重载等),初期编写成本高。但它符合C++容器迭代器的通用范式,调用方可以用熟悉的range-based for循环或标准算法(如
std::for_each、std::count)处理元素,扩展性更强。比如需要统计相邻元素的和、筛选特定元素时,无需修改Matrix类代码,直接结合标准库即可实现。
总结
- 若场景是简单批量处理相邻元素,无需灵活遍历控制,闭包Lambda方案更简洁,可读性更好,性能足够用。
- 若需要灵活遍历操作(结合标准算法、中途终止、重复遍历)或追求极致性能,迭代器方案更合适,虽然编写繁琐,但扩展性和性能表现更优。
内容的提问来源于stack exchange,提问作者nowox
相关产品推荐
相关产品推荐

