You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

闭包遍历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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 18:30:54