如何在C++11/14中遍历std::vector的连续元素区间?
C++11/14下遍历std::vector连续元素区间的最优方案
核心问题:消除不必要的元素拷贝
原代码每次循环都会创建临时v_slice并拷贝元素,既浪费性能又冗余。核心优化方向是直接传递区间引用而非拷贝子vector,同时简化循环逻辑。
方案1:修改foo接受迭代器区间(推荐)
把foo改为接受迭代器范围,彻底避免元素拷贝,代码更简洁:
#include <vector> #include <iostream> #include <iterator> template <typename Iter> int foo(Iter begin, Iter end) { std::cout << "["; if (begin != end) { std::cout << *begin; ++begin; for (; begin != end; ++begin) { std::cout << "," << *begin; } } std::cout << "]" << std::endl; return 0; } int main() { std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10}; std::vector<int> v_out; const int n = 3; // 简化循环条件:只要起始位置+n不超出vector末尾就继续 for (auto begin = v.begin(); std::next(begin, n) <= v.end(); ++begin) { auto end = std::next(begin, n); v_out.push_back(foo(begin, end)); } }
方案2:自定义轻量级区间视图类(保留容器式接口)
如果希望foo的调用方式贴近原代码(比如支持范围for循环),可以写一个仅包装迭代器的轻量视图类,完全不拷贝元素:
#include <vector> #include <iostream> #include <iterator> template <typename T> class VectorView { public: using iterator = typename std::vector<T>::const_iterator; VectorView(iterator begin, iterator end) : m_begin(begin), m_end(end) {} iterator begin() const { return m_begin; } iterator end() const { return m_end; } size_t size() const { return std::distance(m_begin, m_end); } const T& operator[](size_t idx) const { return *std::next(m_begin, idx); } private: iterator m_begin; iterator m_end; }; int foo(const VectorView<int>& v) { std::cout << "["; for(int e: v) { std::cout << e << ","; } std::cout << "]" << std::endl; return 0; } int main() { std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10}; std::vector<int> v_out; const int n = 3; for (auto begin = v.begin(); std::next(begin, n) <= v.end(); ++begin) { VectorView<int> view(begin, std::next(begin, n)); v_out.push_back(foo(view)); } }
方案3:适配std::for_each(STL算法风格)
生成所有区间的起始迭代器范围,用std::for_each遍历处理,符合STL编程习惯:
#include <vector> #include <iostream> #include <algorithm> #include <iterator> template <typename Iter> int foo(Iter begin, Iter end) { std::cout << "["; if (begin != end) { std::cout << *begin; ++begin; for (; begin != end; ++begin) { std::cout << "," << *begin; } } std::cout << "]" << std::endl; return 0; } int main() { std::vector<int> v = {0,1,2,3,4,5,6,7,8,9,10}; std::vector<int> v_out; const int n = 3; auto start_begin = v.begin(); auto start_end = std::prev(v.end(), n - 1); // 最后一个合法起始位置 std::for_each(start_begin, ++start_end, [&](auto begin) { auto end = std::next(begin, n); v_out.push_back(foo(begin, end)); }); }
特殊情况:无法修改foo函数
如果必须保留foo(const std::vector<int>&)的接口,只能通过std::move减少临时对象的内存开销,但元素拷贝无法避免:
v_out.push_back(foo(std::vector<int>(begin, end)));
内容的提问来源于stack exchange,提问作者RAM
相关产品推荐
相关产品推荐

